home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / game / shoot / ADescentSrc.lha / descent / main / newdemo.c < prev    next >
Text File  |  1998-08-08  |  110KB  |  3,722 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: /usr/CVS/descent/main/newdemo.c,v $
  15.  * $Revision: 1.2 $
  16.  * $Author: nobody $
  17.  * $Date: 1998/08/08 15:44:40 $
  18.  * 
  19.  * Code to make a complete demo playback system.
  20.  * 
  21.  * $Log: newdemo.c,v $
  22.  * Revision 1.2  1998/08/08 15:44:40  nobody
  23.  * Activated the Editior
  24.  *
  25.  * Revision 1.1.1.1  1998/03/03 15:12:27  nobody
  26.  * reimport after crash from backup
  27.  *
  28.  * Revision 1.1.1.1  1998/02/13  20:20:41  hfrieden
  29.  * Initial Import
  30.  *
  31.  * Revision 2.7  1995/05/26  16:16:06  john
  32.  * Split SATURN into define's for requiring cd, using cd, etc.
  33.  * Also started adding all the Rockwell stuff.
  34.  * 
  35.  * Revision 2.6  1995/03/21  14:39:38  john
  36.  * Ifdef'd out the NETWORK code.
  37.  * 
  38.  * Revision 2.5  1995/03/14  18:24:31  john
  39.  * Force Destination Saturn to use CD-ROM drive.
  40.  * 
  41.  * Revision 2.4  1995/03/14  16:22:29  john
  42.  * Added cdrom alternate directory stuff.
  43.  * 
  44.  * Revision 2.3  1995/03/10  12:58:33  allender
  45.  * only display rear view cockpit when cockpit mode was CM_FULL_COCKPIT.
  46.  * 
  47.  * Revision 2.2  1995/03/08  16:12:15  allender
  48.  * changes for Destination Saturn
  49.  * 
  50.  * Revision 2.1  1995/03/08  12:11:26  allender
  51.  * fix shortpos reading
  52.  * 
  53.  * Revision 2.0  1995/02/27  11:29:40  john
  54.  * New version 2.0, which has no anonymous unions, builds with
  55.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  56.  * 
  57.  * Revision 1.189  1995/02/22  14:53:42  allender
  58.  * missed some anonymous stuff
  59.  * 
  60.  * Revision 1.188  1995/02/22  13:24:53  john
  61.  * Removed the vecmat anonymous unions.
  62.  * 
  63.  * Revision 1.187  1995/02/22  13:13:54  allender
  64.  * remove anonymous unions from object structure
  65.  * 
  66.  * Revision 1.186  1995/02/14  15:36:41  allender
  67.  * fix fix for morph effect
  68.  * 
  69.  * Revision 1.185  1995/02/14  11:25:48  allender
  70.  * save cockpit mode and restore after playback.  get orientation for morph
  71.  * effect when object is morph vclip
  72.  * 
  73.  * Revision 1.184  1995/02/13  12:18:14  allender
  74.  * change to decide about interpolating or not
  75.  * 
  76.  * Revision 1.183  1995/02/12  00:46:23  adam
  77.  * don't decide to skip frames until after at least 10 frames have
  78.  * passed -- allender
  79.  * 
  80.  * Revision 1.182  1995/02/11  22:34:01  john
  81.  * Made textures page in for newdemos before playback time.
  82.  * 
  83.  * Revision 1.181  1995/02/11  17:28:32  allender
  84.  * strip frames from end of demo
  85.  * 
  86.  * Revision 1.180  1995/02/11  16:40:35  allender
  87.  * start of frame stripping debug code
  88.  * 
  89.  * Revision 1.179  1995/02/10  17:40:06  allender
  90.  * put back in wall_hit_process code to fix door problem
  91.  * 
  92.  * Revision 1.178  1995/02/10  17:17:24  adam
  93.  * allender } fix
  94.  * 
  95.  * Revision 1.177  1995/02/10  17:16:24  allender
  96.  * fix possible tmap problems
  97.  * 
  98.  * Revision 1.176  1995/02/10  15:54:37  allender
  99.  * changes for out of space on device.
  100.  * 
  101.  * Revision 1.175  1995/02/09  19:55:00  allender
  102.  * fix bug with morph recording -- force rendertype to RT_POLYOBJ when
  103.  * playing back since it won't render until fully morphed otherwise
  104.  * 
  105.  * Revision 1.174  1995/02/07  17:15:35  allender
  106.  * DOH!!!!!
  107.  * 
  108.  * Revision 1.173  1995/02/07  17:14:21  allender
  109.  * immediately return when loading bogus level stuff when reading a frame
  110.  * 
  111.  * Revision 1.172  1995/02/02  11:15:03  allender
  112.  * after loading new level, read next frame (forward or back) always because
  113.  * of co-op ships showing up when level is loaded
  114.  * 
  115.  * Revision 1.171  1995/02/02  10:24:16  allender
  116.  * removed cfile stuff.  Use standard FILE functions for demo playback
  117.  * 
  118.  * Revision 1.170  1995/01/30  13:54:32  allender
  119.  * support for missions
  120.  * 
  121.  * Revision 1.169  1995/01/27  16:27:35  allender
  122.  * put game mode to demo_game_mode when sorting multiplayer kill (and score)
  123.  * list
  124.  * 
  125.  * Revision 1.168  1995/01/27  09:52:25  allender
  126.  * minor changes because of object/segment linking problems
  127.  * 
  128.  * Revision 1.167  1995/01/27  09:22:28  allender
  129.  * changed way multi-player score is recorded.  Record difference, not
  130.  * actual
  131.  * 
  132.  * Revision 1.166  1995/01/25  14:32:44  allender
  133.  * changed with recorded player flags.  More checks for paused state
  134.  * during interpolation reading of objects
  135.  * 
  136.  * Revision 1.165  1995/01/25  11:23:32  allender
  137.  * found bug with out of disk space problem
  138.  * 
  139.  * Revision 1.164  1995/01/25  11:11:33  allender
  140.  * coupla' things.  Fix problem with objects apparently being linked in
  141.  * the wrong segment.  Put an Int3 in to check why demos will write to
  142.  * end of space on drive. close demo file if demo doens't start playing
  143.  * back.  Put obj->type == OBJ_ROBOT around checking for boss cloaking
  144.  * 
  145.  * Revision 1.163  1995/01/24  19:44:30  allender
  146.  * fix obscure problem with rewinding and having the wrong object linked
  147.  * to the wrong segments.  will investigate further.
  148.  * 
  149.  * Revision 1.162  1995/01/23  09:31:28  allender
  150.  * add team score in team mode playback
  151.  * 
  152.  * Revision 1.161  1995/01/20  22:47:39  matt
  153.  * Mission system implemented, though imcompletely
  154.  * 
  155.  * Revision 1.160  1995/01/20  09:30:37  allender
  156.  * don't call LoadLevel with bogus data
  157.  * 
  158.  * Revision 1.159  1995/01/20  09:13:23  allender
  159.  * *&^%&*%$ typo
  160.  * 
  161.  * Revision 1.158  1995/01/20  09:12:04  allender
  162.  * record team names during demo recoring in GM_TEAM
  163.  * 
  164.  * Revision 1.157  1995/01/19  16:31:09  allender
  165.  * forgot to bump demo version for new weapon change stuff
  166.  * 
  167.  * Revision 1.156  1995/01/19  16:29:33  allender
  168.  * added new byte for weapon change (old weapon) so rewinding works
  169.  * correctly for weapon changes in registered
  170.  * 
  171.  * Revision 1.155  1995/01/19  15:00:05  allender
  172.  * remove code to take away blastable walls in multiplayer demo playbacks
  173.  * 
  174.  * Revision 1.154  1995/01/19  11:07:05  allender
  175.  * put in psuedo cloaking for boss robots.  Problem is that cloaking is
  176.  * time based, and that don't get done in demos, so bosses just disappear.
  177.  * oh well
  178.  * 
  179.  * Revision 1.153  1995/01/19  09:42:29  allender
  180.  * record laser levels in demos
  181.  * 
  182.  * Revision 1.152  1995/01/18  20:43:12  allender
  183.  * fix laser level stuff on goto-beginning and goto-end
  184.  * 
  185.  * Revision 1.151  1995/01/18  20:28:18  allender
  186.  * cloak robots now cloak (except maybe for boss........)  Put in function
  187.  * to deal with control center triggers
  188.  * 
  189.  * Revision 1.150  1995/01/18  18:55:07  allender
  190.  * bug fix
  191.  * 
  192.  * Revision 1.149  1995/01/18  18:49:03  allender
  193.  * lots 'o stuff....record laser level.  Record beginning of door opening
  194.  * sequence.  Fix some problems with control center stuff.  Control center
  195.  * triggers now work in reverse
  196.  * 
  197.  * Revision 1.148  1995/01/18  08:51:40  allender
  198.  * forgot to record ammo counts at beginning of demo
  199.  * 
  200.  * Revision 1.147  1995/01/17  17:42:07  allender
  201.  * added primary and secondary ammo counts.  Changed goto_end routine
  202.  * to be more efficient
  203.  * 
  204.  * Revision 1.146  1995/01/17  13:46:35  allender
  205.  * fix problem with destroyed control center and rewinding a demo.
  206.  * Save callsign and restore after demo playback
  207.  * 
  208.  * Revision 1.145  1995/01/12  10:21:53  allender
  209.  * fixes for 1.0 to 1.1 demo incompatibility
  210.  * 
  211.  * Revision 1.144  1995/01/05  13:51:43  allender
  212.  * fixed type of player num variable
  213.  * 
  214.  * Revision 1.143  1995/01/04  16:58:28  allender
  215.  * bumped up demo version number
  216.  * 
  217.  * Revision 1.142  1995/01/04  14:59:02  allender
  218.  * added more information to end of demo for registered.  Forced game mode
  219.  * to be GM_NORMAL on demo playback
  220.  * 
  221.  * Revision 1.141  1995/01/03  17:30:47  allender
  222.  * fixed logic problem with cloak stuf
  223.  * 
  224.  * Revision 1.140  1995/01/03  17:12:23  allender
  225.  * fix for getting cloak stuff at end of demo for shareware
  226.  * 
  227.  * Revision 1.139  1995/01/03  15:20:24  allender
  228.  * fix goto_end for shareware -- changes to goto_end for registered
  229.  * 
  230.  * Revision 1.138  1995/01/03  13:13:26  allender
  231.  * add } I forgot
  232.  * 
  233.  * Revision 1.137  1995/01/03  13:10:29  allender
  234.  * make score work forwards and backwards
  235.  * 
  236.  * Revision 1.136  1995/01/03  11:45:20  allender
  237.  * added code to record players scores
  238.  * 
  239.  * Revision 1.135  1994/12/30  10:03:57  allender
  240.  * put cloak stuff at end of demo for fast forward to the end
  241.  * 
  242.  * Revision 1.134  1994/12/29  17:02:55  allender
  243.  * spelling fix on SHAREWARE
  244.  * 
  245.  * Revision 1.133  1994/12/29  16:43:41  allender
  246.  * lots of new multiplayer stuff.  wrapped much code with SHAREWARE defines
  247.  * 
  248.  * Revision 1.132  1994/12/28  14:15:01  allender
  249.  * added routines to deal with connecting and reconnecting players when
  250.  * recording multiplayer demos
  251.  * 
  252.  * Revision 1.131  1994/12/21  12:57:59  allender
  253.  * bug fix
  254.  * 
  255.  * Revision 1.130  1994/12/21  12:46:53  allender
  256.  * record multi player deaths and kills
  257.  * 
  258.  * Revision 1.129  1994/12/19  16:37:27  allender
  259.  * pick good filename when trying to save in network play and player
  260.  * gets bumped out of menu by multi-player code
  261.  * 
  262.  * Revision 1.128  1994/12/14  10:49:01  allender
  263.  * reset bad_read variable when starting demo playback
  264.  * 
  265.  * Revision 1.127  1994/12/14  08:53:06  allender
  266.  * lowered watermark for out of space
  267.  * 
  268.  * Revision 1.126  1994/12/14  08:49:52  allender
  269.  * put up warning when starting demo recording if not enough space and
  270.  * not let them record
  271.  * 
  272.  * Revision 1.125  1994/12/13  00:01:37  allender
  273.  * CLOAK FIX -- (I'm tempted to take cloak out of game because I can't
  274.  * seem to get it right in demo playback)
  275.  * 
  276.  * Revision 1.124  1994/12/12  14:51:21  allender
  277.  * more fixed to multiplayer cloak stuff
  278.  * 
  279.  * Revision 1.123  1994/12/12  11:33:11  allender
  280.  * fixed rearview mode to work again
  281.  * 
  282.  * Revision 1.122  1994/12/12  11:00:16  matt
  283.  * Added code to handle confusion with attached objects
  284.  * 
  285.  * Revision 1.121  1994/12/12  00:31:29  allender
  286.  * give better warning when out of space when recording.  Don't record
  287.  * until no space left.  We have 500K watermark when we now stop recording
  288.  * 
  289.  * Revision 1.120  1994/12/10  16:44:54  matt
  290.  * Added debugging code to track down door that turns into rock
  291.  * 
  292.  * Revision 1.119  1994/12/09  18:46:15  matt
  293.  * Added code to handle odd error condition
  294.  * 
  295.  * Revision 1.118  1994/12/09  17:27:37  allender
  296.  * force playernum to 0 when demo is done playing
  297.  * 
  298.  * Revision 1.117  1994/12/09  16:40:39  allender
  299.  * yet more cloak stuff.  Assign cloak/invuln time when starting demo
  300.  * if flags are set.  Check cloak and invuln time when demo
  301.  * even when paused
  302.  * 
  303.  * Revision 1.116  1994/12/09  14:59:22  matt
  304.  * Added system to attach a fireball to another object for rendering purposes,
  305.  * so the fireball always renders on top of (after) the object.
  306.  * 
  307.  * Revision 1.115  1994/12/09  12:21:45  allender
  308.  * only allow valid chars when typing in demo filename
  309.  * 
  310.  * Revision 1.114  1994/12/08  23:19:02  allender
  311.  * final(?) fix for getting cloak gauge to work on demo playback
  312.  * with forward and reverse
  313.  * 
  314.  * Revision 1.113  1994/12/08  21:34:38  allender
  315.  * record old and new player flags to accuratedly record cloaking and
  316.  * decloaking
  317.  * ./
  318.  * 
  319.  * Revision 1.112  1994/12/08  18:04:47  allender
  320.  * bashed playernum right after reading it in demo header so shields
  321.  * and energy are put in right place
  322.  * 
  323.  * Revision 1.111  1994/12/08  17:10:07  allender
  324.  * encode playernum in demo header.  Bash viewer segment to 0 if in
  325.  * bogus segnum.  Don't link render objs for same reason
  326.  * 
  327.  * Revision 1.110  1994/12/08  15:36:12  allender
  328.  * cloak stuff works forwards and backwards
  329.  * 
  330.  * Revision 1.109  1994/12/08  13:46:03  allender
  331.  * don't record rearview anymore, but leave in case statement for playback
  332.  * purposes.  change the way letterbox <--> cockpit transitions happen
  333.  * 
  334.  * Revision 1.108  1994/12/08  12:36:06  matt
  335.  * Added new object allocation & deallocation functions so other code
  336.  * could stop messing around with internal object data structures.
  337.  * 
  338.  * Revision 1.107  1994/12/08  11:19:04  allender
  339.  * handle out of space (more) gracefully then before
  340.  * 
  341.  * Revision 1.106  1994/12/08  00:29:49  allender
  342.  * fixed bug that didn't load level on goto_beginning
  343.  * 
  344.  * Revision 1.105  1994/12/08  00:11:51  mike
  345.  * change matrix interpolation.
  346.  * 
  347.  * Revision 1.104  1994/12/07  23:46:37  allender
  348.  * changed invulnerability and cloak to work (almost) correctly both
  349.  * in single and multi player
  350.  * 
  351.  * Revision 1.103  1994/12/07  11:48:49  adam
  352.  * BY ALLENDER -- added dampening of interpolation factor to 1 if greater
  353.  * than 1 (although I have not seen this happen).  this is attempt to
  354.  * get wobbling problem solved
  355.  * 
  356.  * Revision 1.102  1994/12/07  11:23:56  allender
  357.  * attempt at getting rid of wobbling on demo playback
  358.  * 
  359.  * Revision 1.101  1994/12/06  19:31:17  allender
  360.  * moved blastable wall stuff code to where we load level during demo
  361.  * playback
  362.  * 
  363.  * Revision 1.100  1994/12/06  19:21:51  allender
  364.  * multi games, destroy blastable walls.  Do wall toggle when control center
  365.  * destroyed
  366.  * 
  367.  * Revision 1.99  1994/12/06  16:54:48  allender
  368.  * fixed code so if demo automatically started from menu, don't bring up
  369.  * message if demo is too old
  370.  * 
  371.  * Revision 1.98  1994/12/06  13:55:15  matt
  372.  * Use new rounding func, f2ir()
  373.  * 
  374.  * Revision 1.97  1994/12/06  13:44:45  allender
  375.  * suppressed compiler warnings
  376.  * 
  377.  * Revision 1.96  1994/12/06  13:38:03  allender
  378.  * removed recording of wall hit process.  I think that all bases are covered
  379.  * elsewhere
  380.  * 
  381.  * Revision 1.95  1994/12/06  12:57:35  allender
  382.  * added recording of multi_decloaking.  Fixed some other cloaking code so
  383.  * that cloak should last as long as player was cloaked.  We will lose the
  384.  * guage effect, but the time is probably more important on playback
  385.  * 
  386.  * Revision 1.94  1994/12/05  23:37:17  matt
  387.  * Took out calls to warning() function
  388.  * 
  389.  * Revision 1.93  1994/12/03  17:52:04  yuan
  390.  * Localization 380ish
  391.  * 
  392.  * Revision 1.92  1994/12/02  12:53:39  allender
  393.  * fixed goto_beginning and goto_end on demo playback
  394.  * 
  395.  * Revision 1.91  1994/12/01  12:01:49  allender
  396.  * added multi player cloak stuff
  397.  * 
  398.  * Revision 1.90  1994/11/30  09:33:58  allender
  399.  * added field in header to tell what version (shareware or registered)
  400.  * demo was recorded with.  Don't allow demo recorded on one to playback
  401.  * on the other
  402.  * 
  403.  * Revision 1.89  1994/11/29  00:31:01  allender
  404.  * major changes -- added level recording feature which records level
  405.  * advancement.  Changes to internal code to handle this.
  406.  * 
  407.  * Revision 1.88  1994/11/27  23:13:54  matt
  408.  * Made changes for new mprintf calling convention
  409.  * 
  410.  * Revision 1.87  1994/11/27  23:07:35  allender
  411.  * starting on code to get all level transitions recorded. not done yet
  412.  * 
  413.  * Revision 1.86  1994/11/27  17:39:47  matt
  414.  * Don't xlate tmap numbers when editor compiled out
  415.  * 
  416.  * Revision 1.85  1994/11/23  09:27:21  allender
  417.  * put up info box with message if demo version is too old or level
  418.  * cannot be loaded
  419.  * 
  420.  * Revision 1.84  1994/11/22  19:37:39  allender
  421.  * fix array mistake
  422.  * 
  423.  * Revision 1.83  1994/11/22  19:35:09  allender
  424.  * record player ship colors in multiplayer demo recordings
  425.  * 
  426.  * Revision 1.82  1994/11/19  15:36:42  mike
  427.  * fix fix.
  428.  * 
  429.  * Revision 1.81  1994/11/19  15:23:21  mike
  430.  * rip out unused code
  431.  * 
  432.  * Revision 1.80  1994/11/16  14:51:49  rob
  433.  * Fixed network/demo incompatibility.
  434.  * 
  435.  * Revision 1.79  1994/11/15  10:55:48  allender
  436.  * made start of demo playback read initial demo information so
  437.  * level will get loaded.  Made demo record to single file which
  438.  * will get renamed.  Added numerics after old filename so
  439.  * sequential filenames would be defaulted to
  440.  * 
  441.  * Revision 1.78  1994/11/15  09:46:06  allender
  442.  * added versioning.  Fixed problems with trying to interpolating a completely
  443.  * 0 orientation matrix
  444.  * 
  445.  * Revision 1.77  1994/11/14  14:34:31  matt
  446.  * Fixed up handling when textures can't be found during remap
  447.  * 
  448.  * Revision 1.76  1994/11/14  09:15:29  allender
  449.  * make ESC from file save menu exit w/o saving.  Fix letterbox, rear view,
  450.  * to normal cockpit mode transition to work correctly when skipping and
  451.  * interpolating frames
  452.  * 
  453.  * Revision 1.75  1994/11/11  16:22:07  allender
  454.  * made morphing objects record only the object being morphed.
  455.  * 
  456.  * Revision 1.74  1994/11/08  14:59:19  john
  457.  * Added code to respond to network while in menus.
  458.  * 
  459.  * Revision 1.73  1994/11/08  14:52:20  adam
  460.  * *** empty log message ***
  461.  * 
  462.  * Revision 1.72  1994/11/07  15:47:04  allender
  463.  * prompt for filename when done recording demo
  464.  * 
  465.  * Revision 1.71  1994/11/07  11:47:19  allender
  466.  * when interpolating frames, delete weapon, fireball, and debris objects
  467.  * from an inpolated frame if they don't appear in the next recorded
  468.  * frame
  469.  * 
  470.  * Revision 1.70  1994/11/07  11:02:41  allender
  471.  * more with interpolation. I believe that I have it right now
  472.  * 
  473.  * Revision 1.69  1994/11/07  08:47:40  john
  474.  * Made wall state record.
  475.  * 
  476.  * Revision 1.68  1994/11/05  17:22:51  john
  477.  * Fixed lots of sequencing problems with newdemo stuff.
  478.  * 
  479.  * Revision 1.67  1994/11/04  20:11:52  john
  480.  * Neatening up palette stuff with demos.
  481.  * 
  482.  * Revision 1.66  1994/11/04  16:49:44  allender
  483.  * changed newdemo_do_interpolate to default to on
  484.  * 
  485.  * Revision 1.65  1994/11/04  16:44:51  allender
  486.  * added filename support for demo recording.  more auto demo stuff
  487.  * 
  488.  * Revision 1.64  1994/11/04  13:05:31  allender
  489.  * fixing the lifeleft variable again.  (I think I got it right this time)
  490.  * 
  491.  * Revision 1.63  1994/11/04  11:37:37  allender
  492.  * commented out fprintfs and fixed compiler warning
  493.  * 
  494.  * Revision 1.62  1994/11/04  11:33:50  allender
  495.  * added OBJ_FLARE and OBJ_LIGHT to obj->lifeleft recording
  496.  * 
  497.  * Revision 1.61  1994/11/04  11:29:21  allender
  498.  * more interpolation stuff -- not done yet.  Fixed so hostage vclips
  499.  * render correctly.  Changed lifeleft to full precision, but only
  500.  * write it when object is fireball or weapon type of object
  501.  * 
  502.  * Revision 1.60  1994/11/03  10:00:11  allender
  503.  * fixed divide by zero in calculating render time.  more interpolation
  504.  * stuff which isn't quite done
  505.  * 
  506.  * Revision 1.59  1994/11/02  17:10:59  allender
  507.  * never play recorded frames when interpolation is occuring
  508.  * 
  509.  * Revision 1.58  1994/11/02  14:28:58  allender
  510.  * profile total playback time and average frame render time
  511.  * 
  512.  * Revision 1.57  1994/11/02  14:09:03  allender
  513.  * record rear view.  start of playback interpolation code -- this
  514.  * is not yet done
  515.  * 
  516.  * Revision 1.56  1994/11/01  13:25:30  allender
  517.  * drop frames if playing back demo on slower machine
  518.  * 
  519.  * Revision 1.55  1994/10/31  16:10:40  allender
  520.  * record letterbox mode on death seq, and then restore
  521.  * 
  522.  * Revision 1.54  1994/10/29  16:01:38  allender
  523.  * added ND_STATE_NODEMOS to indicate that there are no demos currently
  524.  * available for playback
  525.  * 
  526.  * Revision 1.53  1994/10/29  15:38:42  allender
  527.  * in newdemo_start_playback, make Newdemo_at_eof = 0
  528.  * 
  529.  * Revision 1.52  1994/10/28  14:45:28  john
  530.  * fixed typo from last checkin.
  531.  * 
  532.  * Revision 1.51  1994/10/28  14:42:55  john
  533.  * Added sound volumes to all sound calls.
  534.  * 
  535.  * Revision 1.50  1994/10/28  14:31:57  allender
  536.  * homing missle and autodemo stuff
  537.  * 
  538.  * Revision 1.49  1994/10/28  12:42:14  allender
  539.  * record homing distance
  540.  * 
  541.  * Revision 1.48  1994/10/27  16:57:54  allender
  542.  * changed demo vcr to be able to play any number of frames by storing
  543.  * frame length (in bytes) in the demo file.  Added blowing up monitors
  544.  * 
  545.  * Revision 1.47  1994/10/26  16:50:50  allender
  546.  * put two functions inside of VCR_MODE ifdef
  547.  * 
  548.  * Revision 1.46  1994/10/26  15:20:32  allender
  549.  * added CT_REMOTE as valid control type for recording
  550.  * 
  551.  * Revision 1.45  1994/10/26  14:45:35  allender
  552.  * completed hacked in vcr demo playback stuff
  553.  * 
  554.  * Revision 1.44  1994/10/26  13:40:52  allender
  555.  * vcr playback of demo stuff
  556.  * 
  557.  * Revision 1.43  1994/10/26  08:51:57  allender
  558.  * record player weapon change
  559.  * 
  560.  * Revision 1.42  1994/10/25  15:48:01  allender
  561.  * add shields, energy, and player flags to demo recording.
  562.  * ,
  563.  * 
  564.  * Revision 1.41  1994/10/24  08:19:35  allender
  565.  * fixed compilation errors
  566.  * 
  567.  * Revision 1.40  1994/10/23  19:17:08  matt
  568.  * Fixed bug with "no key" messages
  569.  * 
  570.  * Revision 1.39  1994/10/22  14:15:08  mike
  571.  * Suppress compiler warnings.
  572.  * 
  573.  * Revision 1.38  1994/10/21  15:24:55  allender
  574.  * compressed writing of object structures with specialized code
  575.  * to write out only pertinent object structures.
  576.  * 
  577.  * Revision 1.37  1994/10/20  13:03:17  matt
  578.  * Replaced old save files (MIN/SAV/HOT) with new LVL files
  579.  * 
  580.  * Revision 1.36  1994/09/28  23:13:10  matt
  581.  * Macroized palette flash system
  582.  * 
  583.  * Revision 1.35  1994/09/26  17:28:32  matt
  584.  * Made new multiple-object morph code work with the demo system
  585.  * 
  586.  * Revision 1.34  1994/09/10  13:31:54  matt
  587.  * Made exploding walls a type of blastable walls.
  588.  * Cleaned up blastable walls, making them tmap2 bitmaps.
  589.  * 
  590.  * Revision 1.33  1994/08/15  18:05:28  john
  591.  * *** empty log message ***
  592.  * 
  593.  * Revision 1.32  1994/08/15  17:56:38  john
  594.  * ,
  595.  * 
  596.  * Revision 1.31  1994/08/10  09:44:54  john
  597.  * *** empty log message ***
  598.  * 
  599.  * Revision 1.30  1994/07/22  12:35:48  matt
  600.  * Cleaned up editor/game interactions some more.
  601.  * 
  602.  * Revision 1.29  1994/07/21  13:06:45  matt
  603.  * Ripped out remants of old demo system, and added demo only system that
  604.  * disables object movement and game options from menu.
  605.  * 
  606.  * Revision 1.28  1994/07/18  16:22:44  john
  607.  * Made all file read/writes call the same routine.
  608.  * 
  609.  * Revision 1.27  1994/07/14  22:38:27  matt
  610.  * Added exploding doors
  611.  * 
  612.  * Revision 1.26  1994/07/05  12:49:04  john
  613.  * Put functionality of New Hostage spec into code.
  614.  * 
  615.  * Revision 1.25  1994/06/29  11:05:38  john
  616.  * Made demos read in compressed.
  617.  * 
  618.  * Revision 1.24  1994/06/29  09:14:06  john
  619.  * Made files write out uncompressed and read in compressed.
  620.  * 
  621.  * Revision 1.23  1994/06/28  11:55:28  john
  622.  * Made newdemo system record/play directly to/from disk, so
  623.  * we don't need the 4 MB buffer anymore.
  624.  * 
  625.  * Revision 1.22  1994/06/27  15:52:38  john
  626.  * #define'd out the newdemo stuff
  627.  * 
  628.  * 
  629.  * Revision 1.21  1994/06/22  00:29:04  john
  630.  * Fixed bug with playing demo then playing game without
  631.  * loading new mine.
  632.  * 
  633.  * Revision 1.20  1994/06/22  00:14:23  john
  634.  * Attempted to fix sign.
  635.  * 
  636.  * Revision 1.19  1994/06/21  23:57:54  john
  637.  * Hopefully fixed bug with negative countdowns.
  638.  * 
  639.  * Revision 1.18  1994/06/21  23:47:44  john
  640.  * MAde Malloc always 4*1024*1024.
  641.  * 
  642.  * Revision 1.17  1994/06/21  22:58:47  john
  643.  * Added error if out of memory.
  644.  * 
  645.  * Revision 1.16  1994/06/21  22:15:48  john
  646.  * Added  % done to demo recording.
  647.  * 
  648.  * 
  649.  * Revision 1.15  1994/06/21  19:45:55  john
  650.  * Added palette effects to demo recording.
  651.  * 
  652.  * Revision 1.14  1994/06/21  15:08:54  john
  653.  * Made demo record HUD message and cleaned up the HUD code.
  654.  * 
  655.  * Revision 1.13  1994/06/21  14:20:08  john
  656.  * Put in hooks to record HUD messages.
  657.  * 
  658.  * Revision 1.12  1994/06/20  11:50:15  john
  659.  * Made demo record flash effect, and control center triggers.
  660.  * 
  661.  * Revision 1.11  1994/06/17  18:01:33  john
  662.  * A bunch of new stuff by John
  663.  * 
  664.  * Revision 1.10  1994/06/17  12:13:31  john
  665.  * More newdemo stuff; made editor->game transition start in slew mode.
  666.  * 
  667.  * Revision 1.9  1994/06/16  13:14:36  matt
  668.  * Fixed typo
  669.  * 
  670.  * Revision 1.8  1994/06/16  13:02:07  john
  671.  * Added morph hooks.
  672.  * 
  673.  * Revision 1.7  1994/06/15  19:01:33  john
  674.  * Added the capability to make 3d sounds play just once for the
  675.  * laser hit wall effects.
  676.  * 
  677.  * Revision 1.6  1994/06/15  14:56:59  john
  678.  * Added triggers to demo recording.
  679.  * 
  680.  * Revision 1.5  1994/06/14  20:42:15  john
  681.  * Made robot matztn cntr not work until no robots or player are
  682.  * in the segment.
  683.  * 
  684.  * Revision 1.4  1994/06/14  14:43:27  john
  685.  * Made doors work with newdemo system.
  686.  * 
  687.  * Revision 1.3  1994/06/14  11:32:29  john
  688.  * Made Newdemo record & restore the current mine.
  689.  * 
  690.  * Revision 1.2  1994/06/13  21:02:43  john
  691.  * Initial version of new demo recording system.
  692.  * 
  693.  * Revision 1.1  1994/06/13  11:09:00  john
  694.  * Initial revision
  695.  * 
  696.  * 
  697.  */
  698.  
  699.  
  700. #pragma off (unreferenced)
  701. static char rcsid[] = "$Id: newdemo.c,v 1.2 1998/08/08 15:44:40 nobody Exp $";
  702. #pragma on (unreferenced)
  703.  
  704. #include <stdlib.h>
  705. #include <stdio.h>
  706. #include <string.h> // for memset
  707. #include <ctype.h>
  708. #include <malloc.h>
  709. #include <limits.h>
  710. #include <glob.h>
  711.  
  712. #include "inferno.h"
  713. #include "game.h"
  714. #include "gr.h"
  715. #include "stdlib.h"
  716. #include "bm.h"
  717. //#include "error.h"
  718. #include "mono.h"
  719. #include "3d.h"
  720. #include "segment.h"
  721. #include "texmap.h"
  722. #include "laser.h"
  723. #include "key.h"
  724. #include "gameseg.h"
  725.  
  726. #include "object.h"
  727. #include "physics.h"
  728. #include "slew.h"       
  729. #include "render.h"
  730. #include "wall.h"
  731. #include "vclip.h"
  732. #include "polyobj.h"
  733. #include "fireball.h"
  734. #include "laser.h"
  735. #include "error.h"
  736. #include "ai.h"
  737. #include "hostage.h"
  738. #include "morph.h"
  739.  
  740. #include "powerup.h"
  741. #include "fuelcen.h"
  742.  
  743. #include "sounds.h"
  744. #include "collide.h"
  745.  
  746. #include "lighting.h"
  747. #include "newdemo.h"
  748. #include "gameseq.h"
  749. #include "gamesave.h"
  750. #include "gamemine.h"
  751. #include "switch.h"
  752. #include "gauges.h"
  753. #include "player.h"
  754. #include "vecmat.h"
  755. #include "newmenu.h"
  756. #include "args.h"
  757. #include "palette.h"
  758. #include "multi.h"
  759. #include "network.h"
  760. #include "text.h"
  761. #include "cntrlcen.h"
  762. #include "aistruct.h"
  763. #include "mission.h"
  764. #include "piggy.h"
  765. #include "byteswap.h"
  766.  
  767. #ifdef EDITOR
  768. #include "editor/editor.h"
  769. #endif
  770.  
  771. //#include "nocfile.h"
  772.  
  773. //Does demo start automatically?
  774. int Auto_demo = 0;
  775.  
  776. #define ND_EVENT_EOF                    0           // EOF
  777. #define ND_EVENT_START_DEMO     1           // Followed by 16 character, NULL terminated filename of .SAV file to use
  778. #define ND_EVENT_START_FRAME        2           // Followed by integer frame number, then a fix FrameTime
  779. #define ND_EVENT_VIEWER_OBJECT  3           // Followed by an object structure
  780. #define ND_EVENT_RENDER_OBJECT  4           // Followed by an object structure
  781. #define ND_EVENT_SOUND              5           // Followed by int soundum
  782. #define ND_EVENT_SOUND_ONCE     6           // Followed by int soundum
  783. #define ND_EVENT_SOUND_3D           7           // Followed by int soundum, int angle, int volume
  784. #define ND_EVENT_WALL_HIT_PROCESS 8         // Followed by int segnum, int side, fix damage 
  785. #define ND_EVENT_TRIGGER            9           // Followed by int segnum, int side, int objnum
  786. #define ND_EVENT_HOSTAGE_RESCUED 10         // Followed by int hostage_type
  787. #define ND_EVENT_SOUND_3D_ONCE  11          // Followed by int soundum, int angle, int volume
  788. #define ND_EVENT_MORPH_FRAME        12          // Followed by ? data
  789. #define ND_EVENT_WALL_TOGGLE        13          // Followed by int seg, int side
  790. #define ND_EVENT_HUD_MESSAGE        14          // Followed by char size, char * string (+null)
  791. #define ND_EVENT_CONTROL_CENTER_DESTROYED 15    // Just a simple flag
  792. #define ND_EVENT_PALETTE_EFFECT 16          // Followed by short r,g,b
  793. #define ND_EVENT_PLAYER_ENERGY   17       // followed by byte energy
  794. #define ND_EVENT_PLAYER_SHIELD   18       // followed by byte shields
  795. #define ND_EVENT_PLAYER_FLAGS    19         // followed by player flags
  796. #define ND_EVENT_PLAYER_WEAPON   20       // followed by weapon type and weapon number
  797. #define ND_EVENT_EFFECT_BLOWUP   21         // followed by segment, side, and pnt
  798. #define ND_EVENT_HOMING_DISTANCE 22         // followed by homing distance
  799. #define ND_EVENT_LETTERBOX       23       // letterbox mode for death seq.
  800. #define ND_EVENT_RESTORE_COCKPIT 24         // restore cockpit after death
  801. #define ND_EVENT_REARVIEW        25         // going to rear view mode
  802. #define ND_EVENT_WALL_SET_TMAP_NUM1 26      // Wall changed
  803. #define ND_EVENT_WALL_SET_TMAP_NUM2 27      // Wall changed
  804. #define ND_EVENT_NEW_LEVEL          28          // followed by level number
  805. #define ND_EVENT_MULTI_CLOAK        29          // followed by player num
  806. #define ND_EVENT_MULTI_DECLOAK  30          // followed by player num
  807. #define ND_EVENT_RESTORE_REARVIEW   31      // restore cockpit after rearview mode
  808.  
  809. #ifndef SHAREWARE
  810. #define ND_EVENT_MULTI_DEATH        32          // with player number
  811. #define ND_EVENT_MULTI_KILL     33          // with player number
  812. #define ND_EVENT_MULTI_CONNECT  34          // with player number
  813. #define ND_EVENT_MULTI_RECONNECT    35          // with player number
  814. #define ND_EVENT_MULTI_DISCONNECT   36      // with player number
  815. #define ND_EVENT_MULTI_SCORE        37          // playernum / score
  816. #define ND_EVENT_PLAYER_SCORE       38          // followed by score
  817. #define ND_EVENT_PRIMARY_AMMO       39          // with old/new ammo count
  818. #define ND_EVENT_SECONDARY_AMMO 40          // with old/new ammo count
  819. #define ND_EVENT_DOOR_OPENING       41          // with segment/side
  820. #define ND_EVENT_LASER_LEVEL        42          // no data
  821. #endif
  822.  
  823. #define LAST_SECRET_LEVEL 0
  824. #define LAST_LEVEL 7
  825.  
  826. #define NORMAL_PLAYBACK         0
  827. #define SKIP_PLAYBACK           1
  828. #define INTERPOLATE_PLAYBACK    2
  829. #define INTERPOL_FACTOR       (F1_0 + (F1_0/5))
  830.  
  831. #ifdef SHAREWARE
  832. #define DEMO_VERSION                5
  833. #else
  834. #define DEMO_VERSION                13
  835. #endif
  836.  
  837. #define DEMO_FILENAME           "tmpdemo.dem"
  838. #define DEMO_MAX_LEVELS         29
  839.  
  840. #ifdef SHAREWARE
  841. #define DEMO_GAME_TYPE 1
  842. #else
  843. #define DEMO_GAME_TYPE 2
  844. #endif
  845.  
  846. char nd_save_callsign[CALLSIGN_LEN+1];
  847. int Newdemo_state = 0;
  848. int Newdemo_vcr_state = 0;
  849. int Newdemo_start_frame = -1;
  850. unsigned int Newdemo_size;
  851. int Newdemo_num_written;
  852. int Newdemo_game_mode;
  853. int Newdemo_old_cockpit;
  854. byte Newdemo_no_space;
  855. byte Newdemo_at_eof;
  856. byte Newdemo_do_interpolate = 1;
  857. byte Newdemo_players_cloaked;
  858. byte Newdemo_warning_given = 0;
  859. byte Newdemo_cntrlcen_destroyed = 0;
  860. static byte nd_bad_read;
  861. int NewdemoFrameCount;
  862. short frame_bytes_written = 0;
  863. fix nd_playback_total;
  864. fix nd_recorded_total;
  865. fix nd_recorded_time;
  866. byte playback_style;
  867.  
  868. FILE *infile;
  869. FILE *outfile;
  870.  
  871. int newdemo_get_percent_done()  {
  872.     if ( Newdemo_state == ND_STATE_PLAYBACK )   {
  873.         return (ftell(infile)*100)/Newdemo_size;
  874.     }
  875.     if ( Newdemo_state == ND_STATE_RECORDING )  {
  876.         return ftell(outfile);
  877.     }
  878.     return 0;
  879. }
  880.  
  881. #define VEL_PRECISION 12
  882.  
  883. void my_extract_shortpos(object *objp, shortpos *spp)
  884. {
  885.     int segnum;
  886.     byte    *sp;
  887.  
  888.     sp = spp->bytemat;
  889.     objp->orient.rvec.x = *sp++ << MATRIX_PRECISION;
  890.     objp->orient.uvec.x = *sp++ << MATRIX_PRECISION;
  891.     objp->orient.fvec.x = *sp++ << MATRIX_PRECISION;
  892.  
  893.     objp->orient.rvec.y = *sp++ << MATRIX_PRECISION;
  894.     objp->orient.uvec.y = *sp++ << MATRIX_PRECISION;
  895.     objp->orient.fvec.y = *sp++ << MATRIX_PRECISION;
  896.  
  897.     objp->orient.rvec.z = *sp++ << MATRIX_PRECISION;
  898.     objp->orient.uvec.z = *sp++ << MATRIX_PRECISION;
  899.     objp->orient.fvec.z = *sp++ << MATRIX_PRECISION;
  900.  
  901.     segnum = spp->segment;
  902.     objp->segnum = segnum;
  903.  
  904.     objp->pos.x = (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x;
  905.     objp->pos.y = (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y;
  906.     objp->pos.z = (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z;
  907.  
  908.     objp->mtype.phys_info.velocity.x = (spp->velx << VEL_PRECISION);
  909.     objp->mtype.phys_info.velocity.y = (spp->vely << VEL_PRECISION);
  910.     objp->mtype.phys_info.velocity.z = (spp->velz << VEL_PRECISION);
  911. }
  912.  
  913. int newdemo_read( void *buffer, int elsize, int nelem )
  914. {
  915.     int num_read;
  916.     num_read = fread( buffer,elsize,nelem, infile );
  917.     if (ferror(infile) || feof(infile))
  918.         nd_bad_read = -1;
  919.  
  920.     return num_read;
  921. }
  922.  
  923. int newdemo_write( void *buffer, int elsize, int nelem )
  924. {
  925.     int num_written, total_size;
  926.  
  927.     total_size = elsize * nelem;
  928.     frame_bytes_written += total_size;
  929.     Newdemo_num_written += total_size;
  930.     num_written = fwrite( buffer, elsize, nelem, outfile );
  931. //  if ((Newdemo_num_written > Newdemo_size) && !Newdemo_no_space) {
  932. //      Newdemo_no_space=1;
  933. //      newdemo_stop_recording();
  934. //      return -1;
  935. //  }
  936.     if ((Newdemo_num_written > Newdemo_size) && !Newdemo_no_space)
  937.         Newdemo_no_space=1;
  938.     if (num_written == nelem)
  939.         return num_written;
  940.  
  941.     Newdemo_no_space=2;
  942.     newdemo_stop_recording();
  943.     return -1;
  944. }
  945.  
  946. /*
  947.  *  The next bunch of files taken from Matt's gamesave.c.  We have to modify
  948.  *  these since the demo must save more information about objects that
  949.  *  just a gamesave
  950. */
  951.  
  952. static void nd_write_byte(byte b)
  953. {
  954.     newdemo_write(&b, 1, 1);
  955. }
  956.  
  957. static void nd_write_short(short s)
  958. {
  959.     short ss;
  960.  
  961.     ss = swapshort(s);
  962.     newdemo_write(&ss, 2, 1);
  963. }
  964.  
  965. static void nd_write_int(int i)
  966. {
  967.     int si;
  968.  
  969.     si = swapint(i);
  970.     newdemo_write(&si, 4, 1);
  971. }
  972.  
  973. static void nd_write_string(char *str)
  974. {
  975.     nd_write_byte(strlen(str) + 1);
  976.     newdemo_write(str, strlen(str) + 1, 1);
  977. }
  978.  
  979. static void nd_write_fix(fix f)
  980. {
  981.     int si;
  982.  
  983.     si = swapint((int)f);
  984.     newdemo_write(&si, sizeof(fix), 1);
  985. }
  986.  
  987. static void nd_write_fixang(fixang f)
  988. {
  989.     int si;
  990.  
  991.     si = swapint((int)f);
  992.     newdemo_write(&si, sizeof(fixang), 1);
  993. }
  994.  
  995.  
  996. static void nd_write_vector(vms_vector *v)
  997. {
  998.     nd_write_fix(v->x);
  999.     nd_write_fix(v->y);
  1000.     nd_write_fix(v->z);
  1001. }
  1002.  
  1003. static void nd_write_angvec(vms_angvec *v)
  1004. {
  1005.     nd_write_fixang(v->p);
  1006.     nd_write_fixang(v->b);
  1007.     nd_write_fixang(v->h);
  1008. }
  1009.  
  1010. void nd_write_shortpos(object *obj)
  1011. {
  1012.     int i;
  1013.     shortpos sp;
  1014.     ubyte render_type;
  1015.  
  1016.     create_shortpos(&sp, obj);
  1017.  
  1018.     render_type = obj->render_type;
  1019.     if (((render_type == RT_POLYOBJ) || (render_type == RT_HOSTAGE) || (render_type == RT_MORPH)) || (obj->type == OBJ_CAMERA)) {
  1020.         for (i = 0; i < 9; i++)
  1021.             nd_write_byte(sp.bytemat[i]);
  1022.         for (i = 0; i < 9; i++) {
  1023.             if (sp.bytemat[i] != 0)
  1024.                 break;
  1025.         }
  1026.         if (i == 9) {
  1027.             Int3();         // contact Allender about this.
  1028.         }
  1029.     }
  1030.  
  1031.     nd_write_short(sp.xo);
  1032.     nd_write_short(sp.yo);
  1033.     nd_write_short(sp.zo);
  1034.     nd_write_short(sp.segment);
  1035.     nd_write_short(sp.velx);
  1036.     nd_write_short(sp.vely);
  1037.     nd_write_short(sp.velz);
  1038. }
  1039.  
  1040. static void nd_read_byte(byte *b)
  1041. {
  1042.     newdemo_read(b, 1, 1);
  1043. }
  1044.  
  1045. static void nd_read_short(short *s)
  1046. {
  1047.     short ss;
  1048.     newdemo_read(&ss, 2, 1);
  1049.     *s = swapshort(ss);
  1050. }
  1051.  
  1052. static void nd_read_int(int *i)
  1053. {
  1054.     int si;
  1055.     newdemo_read(&si, 4, 1);
  1056.     *i = swapint(si);
  1057. }
  1058.  
  1059. static void nd_read_string(char *str)
  1060. {
  1061.     byte len;
  1062.  
  1063.     nd_read_byte(&len);
  1064.     newdemo_read(str, len, 1);
  1065. }
  1066.  
  1067. static void nd_read_fix(fix *f)
  1068. {
  1069.     int si;
  1070.     newdemo_read(&si, sizeof(fix), 1);
  1071.     *f = (fix)swapint(si);
  1072. }
  1073.  
  1074. static void nd_read_fixang(fixang *f)
  1075. {
  1076.     int si;
  1077.     newdemo_read(&si, sizeof(fixang), 1);
  1078.     *f = (fixang)swapint(si);
  1079. }
  1080.  
  1081. static void nd_read_vector(vms_vector *v)
  1082. {
  1083.     nd_read_fix(&(v->x));
  1084.    nd_read_fix(&(v->y));
  1085.     nd_read_fix(&(v->z));
  1086. }
  1087.  
  1088. static void nd_read_angvec(vms_angvec *v)
  1089. {
  1090.     nd_read_fixang(&(v->p));
  1091.     nd_read_fixang(&(v->b));
  1092.     nd_read_fixang(&(v->h));
  1093. }
  1094.  
  1095. static void nd_read_shortpos(object *obj)
  1096. {
  1097.     shortpos sp;
  1098.     int i;
  1099.     ubyte render_type;
  1100.  
  1101.     render_type = obj->render_type;
  1102.     if (((render_type == RT_POLYOBJ) || (render_type == RT_HOSTAGE) || (render_type == RT_MORPH)) || (obj->type == OBJ_CAMERA)) {
  1103.         for (i = 0; i < 9; i++)
  1104.             nd_read_byte(&(sp.bytemat[i]));
  1105.     }
  1106.  
  1107.     nd_read_short(&(sp.xo));
  1108.     nd_read_short(&(sp.yo));
  1109.     nd_read_short(&(sp.zo));
  1110.     nd_read_short(&(sp.segment));
  1111.     nd_read_short(&(sp.velx));
  1112.     nd_read_short(&(sp.vely));
  1113.     nd_read_short(&(sp.velz));
  1114.  
  1115.     my_extract_shortpos(obj, &sp);
  1116.     if ((obj->id == VCLIP_MORPHING_ROBOT) && (render_type == RT_FIREBALL) && (obj->control_type == CT_EXPLOSION))
  1117.         extract_orient_from_segment(&obj->orient,&Segments[obj->segnum]);
  1118.  
  1119. }
  1120.  
  1121. object *prev_obj=NULL;      //ptr to last object read in
  1122.     
  1123. void nd_read_object(object *obj)
  1124. {
  1125.     memset(obj, 0, sizeof(object));
  1126.  
  1127. /*
  1128.  *  Do render type first, since with render_type == RT_NONE, we
  1129.  *  blow by all other object information
  1130. */
  1131.     nd_read_byte(&(obj->render_type));
  1132.     nd_read_byte(&(obj->type));
  1133.     if ((obj->render_type == RT_NONE) && (obj->type != OBJ_CAMERA))
  1134.         return;
  1135.  
  1136.     nd_read_byte(&(obj->id));
  1137.     nd_read_byte(&(obj->flags));
  1138.     nd_read_short((short *)&(obj->signature));
  1139.     nd_read_shortpos(obj);
  1140.  
  1141.     obj->attached_obj       = -1;
  1142.  
  1143.     switch(obj->type) {
  1144.  
  1145.         case OBJ_HOSTAGE:
  1146.             obj->control_type = CT_POWERUP; 
  1147.             obj->movement_type = MT_NONE;
  1148.             obj->size = HOSTAGE_SIZE;
  1149.             break;
  1150.  
  1151.         case OBJ_ROBOT:
  1152.             obj->control_type = CT_AI;
  1153.             obj->movement_type = MT_PHYSICS;
  1154.             obj->size = Polygon_models[Robot_info[obj->id].model_num].rad;
  1155.             obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
  1156.             obj->rtype.pobj_info.subobj_flags = 0;
  1157.             obj->ctype.ai_info.CLOAKED = (Robot_info[obj->id].cloak_type?1:0);
  1158.             break;
  1159.  
  1160.         case OBJ_POWERUP:
  1161.             obj->control_type = CT_POWERUP;
  1162.             nd_read_byte(&(obj->movement_type));        // might have physics movement
  1163.             obj->size = Powerup_info[obj->id].size;
  1164.             break;
  1165.  
  1166.         case OBJ_PLAYER:
  1167.             obj->control_type = CT_NONE;
  1168.             obj->movement_type = MT_PHYSICS;
  1169.             obj->size = Polygon_models[Player_ship->model_num].rad;
  1170.             obj->rtype.pobj_info.model_num = Player_ship->model_num;
  1171.             obj->rtype.pobj_info.subobj_flags = 0;
  1172.             break;
  1173.  
  1174.         case OBJ_CLUTTER:
  1175.             obj->control_type = CT_NONE;
  1176.             obj->movement_type = MT_NONE;
  1177.             obj->size = Polygon_models[obj->id].rad;
  1178.             obj->rtype.pobj_info.model_num = obj->id;
  1179.             obj->rtype.pobj_info.subobj_flags = 0;
  1180.             break;
  1181.  
  1182.         default:
  1183.             nd_read_byte(&(obj->control_type));
  1184.             nd_read_byte(&(obj->movement_type));
  1185.             nd_read_fix(&(obj->size));
  1186.             break;  
  1187.     }
  1188.  
  1189.  
  1190.     nd_read_vector(&(obj->last_pos));
  1191.     if ((obj->type == OBJ_WEAPON) && (obj->render_type == RT_WEAPON_VCLIP))
  1192.         nd_read_fix(&(obj->lifeleft));
  1193.     else {
  1194.         nd_read_byte((ubyte *)&(obj->lifeleft));
  1195.         obj->lifeleft = (fix)((int)obj->lifeleft << 12);
  1196.     }
  1197.  
  1198. #ifndef SHAREWARE
  1199.     if (obj->type == OBJ_ROBOT) {
  1200.         if (Robot_info[obj->id].boss_flag) {
  1201.             byte cloaked;
  1202.  
  1203.             nd_read_byte(&cloaked);
  1204.             obj->ctype.ai_info.CLOAKED = cloaked;
  1205.         }
  1206.     }
  1207. #endif
  1208.  
  1209.     switch (obj->movement_type) {
  1210.  
  1211.         case MT_PHYSICS:
  1212.             nd_read_vector(&(obj->mtype.phys_info.velocity));
  1213.             nd_read_vector(&(obj->mtype.phys_info.thrust));
  1214.             break;
  1215.  
  1216.         case MT_SPINNING:
  1217.             nd_read_vector(&(obj->mtype.spin_rate));
  1218.             break;
  1219.  
  1220.         case MT_NONE:
  1221.             break;
  1222.  
  1223.         default:
  1224.             Int3();
  1225.     }
  1226.  
  1227.     switch (obj->control_type) {
  1228.  
  1229.         case CT_EXPLOSION:
  1230.  
  1231.             nd_read_fix(&(obj->ctype.expl_info.spawn_time));
  1232.             nd_read_fix(&(obj->ctype.expl_info.delete_time));
  1233.             nd_read_short(&(obj->ctype.expl_info.delete_objnum));
  1234.  
  1235.             obj->ctype.expl_info.next_attach = obj->ctype.expl_info.prev_attach = obj->ctype.expl_info.attach_parent = -1;
  1236.  
  1237.             if (obj->flags & OF_ATTACHED) {     //attach to previous object
  1238.                 Assert(prev_obj!=NULL);
  1239.                 if (prev_obj->control_type == CT_EXPLOSION) {
  1240.                     if (prev_obj->flags & OF_ATTACHED && prev_obj->ctype.expl_info.attach_parent!=-1)
  1241.                         obj_attach(&Objects[prev_obj->ctype.expl_info.attach_parent],obj);
  1242.                     else
  1243.                         obj->flags &= ~OF_ATTACHED;
  1244.                 }
  1245.                 else
  1246.                     obj_attach(prev_obj,obj);
  1247.             }
  1248.  
  1249.             break;
  1250.  
  1251.         case CT_LIGHT:
  1252.             nd_read_fix(&(obj->ctype.light_info.intensity));
  1253.             break;
  1254.  
  1255.         case CT_AI:
  1256.         case CT_WEAPON:
  1257.         case CT_NONE:
  1258.         case CT_FLYING:
  1259.         case CT_DEBRIS:
  1260.         case CT_POWERUP:
  1261.         case CT_SLEW:
  1262.         case CT_CNTRLCEN:
  1263.         case CT_REMOTE:
  1264.         case CT_MORPH:
  1265.             break;
  1266.  
  1267.         case CT_FLYTHROUGH:
  1268.         case CT_REPAIRCEN:
  1269.         default:
  1270.             Int3();
  1271.     
  1272.     }
  1273.  
  1274.     switch (obj->render_type) {
  1275.  
  1276.         case RT_NONE:
  1277.             break;
  1278.  
  1279.         case RT_MORPH:
  1280.         case RT_POLYOBJ: {
  1281.             int i, tmo;
  1282.  
  1283.             if ((obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_CLUTTER)) {
  1284.                 nd_read_int(&(obj->rtype.pobj_info.model_num));
  1285.                 nd_read_int(&(obj->rtype.pobj_info.subobj_flags));
  1286.             }
  1287.  
  1288.             if ((obj->type != OBJ_PLAYER) && (obj->type != OBJ_DEBRIS))
  1289. #if 0
  1290.                 for (i=0;i<MAX_SUBMODELS;i++)
  1291.                     nd_read_angvec(&(obj->pobj_info.anim_angles[i]));
  1292. #endif
  1293.                 for (i = 0; i < Polygon_models[obj->rtype.pobj_info.model_num].n_models; i++)
  1294.                     nd_read_angvec(&obj->rtype.pobj_info.anim_angles[i]);
  1295.  
  1296.             nd_read_int(&tmo);
  1297.  
  1298.             #ifndef EDITOR
  1299.             obj->rtype.pobj_info.tmap_override  = tmo;
  1300.             #else
  1301.             if (tmo==-1)
  1302.                 obj->rtype.pobj_info.tmap_override  = -1;
  1303.             else {
  1304.                 int xlated_tmo = tmap_xlate_table[tmo];
  1305.                 if (xlated_tmo < 0) {
  1306. //                  mprintf( (0, "Couldn't find texture for demo object, model_num = %d\n", obj->pobj_info.model_num));
  1307.                     Int3();
  1308.                     xlated_tmo = 0;
  1309.                 }
  1310.                 obj->rtype.pobj_info.tmap_override  = xlated_tmo;
  1311.             }
  1312.             #endif
  1313.  
  1314.             break;
  1315.         }
  1316.  
  1317.         case RT_POWERUP:
  1318.         case RT_WEAPON_VCLIP:
  1319.         case RT_FIREBALL:
  1320.         case RT_HOSTAGE:
  1321.             nd_read_int(&(obj->rtype.vclip_info.vclip_num));
  1322.             nd_read_fix(&(obj->rtype.vclip_info.frametime));
  1323.             nd_read_byte(&(obj->rtype.vclip_info.framenum));
  1324.             break;
  1325.  
  1326.         case RT_LASER:
  1327.             break;
  1328.  
  1329.         default:
  1330.             Int3();
  1331.  
  1332.     }
  1333.  
  1334.     prev_obj = obj;
  1335. }
  1336.  
  1337. void nd_write_object(object *obj)
  1338. {
  1339.     int life;
  1340.  
  1341. /*
  1342.  *  Do render_type first so on read, we can make determination of
  1343.  *  what else to read in
  1344. */
  1345.     nd_write_byte(obj->render_type);
  1346.     nd_write_byte(obj->type);
  1347.     if ((obj->render_type == RT_NONE) && (obj->type != OBJ_CAMERA))
  1348.         return;
  1349.  
  1350.     nd_write_byte(obj->id);
  1351.     nd_write_byte(obj->flags);
  1352.     nd_write_short((short)obj->signature);
  1353.     nd_write_shortpos(obj);
  1354.  
  1355.     if ((obj->type != OBJ_HOSTAGE) && (obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_POWERUP) && (obj->type != OBJ_CLUTTER)) {
  1356.         nd_write_byte(obj->control_type);
  1357.         nd_write_byte(obj->movement_type);
  1358.         nd_write_fix(obj->size);
  1359.     }
  1360.     if (obj->type == OBJ_POWERUP)
  1361.         nd_write_byte(obj->movement_type);
  1362.  
  1363.     nd_write_vector(&obj->last_pos);
  1364.  
  1365.     if ((obj->type == OBJ_WEAPON) && (obj->render_type == RT_WEAPON_VCLIP))
  1366.         nd_write_fix(obj->lifeleft);
  1367.     else {
  1368.         life = (int)obj->lifeleft;
  1369.         life = life >> 12;
  1370.         if (life > 255)
  1371.             life = 255;
  1372.         nd_write_byte((ubyte)life);
  1373.     }
  1374.  
  1375. #ifndef SHAREWARE
  1376.     if (obj->type == OBJ_ROBOT) {
  1377.         if (Robot_info[obj->id].boss_flag) {
  1378.             if ((GameTime > Boss_cloak_start_time) && (GameTime < Boss_cloak_end_time))
  1379.                 nd_write_byte(1);
  1380.             else
  1381.                 nd_write_byte(0);
  1382.         }
  1383.     }
  1384. #endif
  1385.  
  1386.     switch (obj->movement_type) {
  1387.  
  1388.         case MT_PHYSICS:
  1389.             nd_write_vector(&obj->mtype.phys_info.velocity);
  1390.             nd_write_vector(&obj->mtype.phys_info.thrust);
  1391.             break;
  1392.  
  1393.         case MT_SPINNING:
  1394.             nd_write_vector(&obj->mtype.spin_rate);
  1395.             break;
  1396.  
  1397.         case MT_NONE:
  1398.             break;
  1399.  
  1400.         default:
  1401.             Int3();
  1402.     }
  1403.  
  1404.     switch (obj->control_type) {
  1405.  
  1406.         case CT_AI:
  1407.             break;
  1408.  
  1409.         case CT_EXPLOSION:
  1410.             nd_write_fix(obj->ctype.expl_info.spawn_time);
  1411.             nd_write_fix(obj->ctype.expl_info.delete_time);
  1412.             nd_write_short(obj->ctype.expl_info.delete_objnum);
  1413.             break;
  1414.  
  1415.         case CT_WEAPON:
  1416.             break;
  1417.  
  1418.         case CT_LIGHT:
  1419.  
  1420.             nd_write_fix(obj->ctype.light_info.intensity);
  1421.             break;
  1422.  
  1423.         case CT_NONE:
  1424.         case CT_FLYING:
  1425.         case CT_DEBRIS:
  1426.         case CT_POWERUP:
  1427.         case CT_SLEW:       //the player is generally saved as slew
  1428.         case CT_CNTRLCEN:
  1429.         case CT_REMOTE:
  1430.         case CT_MORPH:
  1431.             break;
  1432.  
  1433.         case CT_REPAIRCEN:
  1434.         case CT_FLYTHROUGH:
  1435.         default:
  1436.             Int3();
  1437.     
  1438.     }
  1439.  
  1440.     switch (obj->render_type) {
  1441.  
  1442.         case RT_NONE:
  1443.             break;
  1444.  
  1445.         case RT_MORPH:
  1446.         case RT_POLYOBJ: {
  1447.             int i;
  1448.  
  1449.             if ((obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_CLUTTER)) {
  1450.                 nd_write_int(obj->rtype.pobj_info.model_num);
  1451.                 nd_write_int(obj->rtype.pobj_info.subobj_flags);
  1452.             }
  1453.  
  1454.             if ((obj->type != OBJ_PLAYER) && (obj->type != OBJ_DEBRIS))
  1455. #if 0
  1456.                 for (i=0;i<MAX_SUBMODELS;i++)
  1457.                     nd_write_angvec(&obj->pobj_info.anim_angles[i]);
  1458. #endif
  1459.                 for (i = 0; i < Polygon_models[obj->rtype.pobj_info.model_num].n_models; i++)
  1460.                     nd_write_angvec(&obj->rtype.pobj_info.anim_angles[i]);
  1461.  
  1462.  
  1463.             nd_write_int(obj->rtype.pobj_info.tmap_override);
  1464.  
  1465.             break;
  1466.         }
  1467.  
  1468.         case RT_POWERUP:
  1469.         case RT_WEAPON_VCLIP:
  1470.         case RT_FIREBALL:
  1471.         case RT_HOSTAGE:
  1472.             nd_write_int(obj->rtype.vclip_info.vclip_num);
  1473.             nd_write_fix(obj->rtype.vclip_info.frametime);
  1474.             nd_write_byte(obj->rtype.vclip_info.framenum);
  1475.             break;
  1476.  
  1477.         case RT_LASER:
  1478.             break;
  1479.  
  1480.         default:
  1481.             Int3();
  1482.  
  1483.     }
  1484.  
  1485. }
  1486.  
  1487. void newdemo_record_start_demo()
  1488. {
  1489. #ifndef SHAREWARE
  1490.     int i;
  1491. #endif
  1492.  
  1493.     stop_time();
  1494.     nd_write_byte(ND_EVENT_START_DEMO);
  1495.     nd_write_byte(DEMO_VERSION);
  1496.     nd_write_byte(DEMO_GAME_TYPE);
  1497.     nd_write_fix(GameTime);
  1498.     if (Game_mode & GM_MULTI)
  1499.         nd_write_int(Game_mode | (Player_num << 16));
  1500.     else
  1501.         nd_write_int(Game_mode);
  1502.  
  1503. #ifdef NETWORK
  1504. #ifdef SHAREWARE
  1505.     if (Game_mode & GM_MULTI)
  1506.         nd_write_byte(Netgame.team_vector);
  1507. #else
  1508.     if (Game_mode & GM_TEAM) {
  1509.         nd_write_byte(Netgame.team_vector);
  1510.         nd_write_string(Netgame.team_name[0]);
  1511.         nd_write_string(Netgame.team_name[1]);
  1512.     }
  1513. #endif
  1514. #endif
  1515.  
  1516. #ifndef SHAREWARE
  1517.  
  1518.     if (Game_mode & GM_MULTI) {
  1519.         nd_write_byte((byte)N_players);
  1520.         for (i = 0; i < N_players; i++) {
  1521.             nd_write_string(Players[i].callsign);
  1522.             nd_write_byte(Players[i].connected);
  1523.  
  1524.             if (Game_mode & GM_MULTI_COOP) {
  1525.                 nd_write_int(Players[i].score);
  1526.             } else {
  1527.                 nd_write_short((short)Players[i].net_killed_total);
  1528.                 nd_write_short((short)Players[i].net_kills_total);
  1529.             }
  1530.         }
  1531.     } else
  1532.         nd_write_int(Players[Player_num].score);
  1533.  
  1534.     for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
  1535.         nd_write_short((short)Players[Player_num].primary_ammo[i]);
  1536.  
  1537.     for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
  1538.         nd_write_short((short)Players[Player_num].secondary_ammo[i]);
  1539.  
  1540.     nd_write_byte((byte)Players[Player_num].laser_level);
  1541.  
  1542. //  Support for missions added here
  1543.  
  1544.     nd_write_string(Current_mission_filename);
  1545.  
  1546. #endif
  1547.  
  1548.     nd_write_byte((byte)(f2ir(Players[Player_num].energy)));
  1549.     nd_write_byte((byte)(f2ir(Players[Player_num].shields)));
  1550.     nd_write_int(Players[Player_num].flags);        // be sure players flags are set
  1551.     nd_write_byte((byte)Primary_weapon);
  1552.     nd_write_byte((byte)Secondary_weapon);
  1553.     Newdemo_start_frame = FrameCount;
  1554.     newdemo_set_new_level(Current_level_num);
  1555.     start_time();
  1556.  
  1557. }
  1558.  
  1559. void newdemo_record_start_frame(int frame_number, fix frame_time )
  1560. {
  1561.     if (Newdemo_no_space) {
  1562.         newdemo_stop_playback();
  1563.         return;
  1564.     }
  1565.  
  1566.     stop_time();
  1567.     frame_number -= Newdemo_start_frame;
  1568.  
  1569.     Assert(frame_number >= 0 );
  1570.  
  1571.     nd_write_byte(ND_EVENT_START_FRAME);
  1572.     nd_write_short(frame_bytes_written - 1);        // from previous frame
  1573.     frame_bytes_written=3;
  1574.     nd_write_int(frame_number);
  1575.     nd_write_int(frame_time);
  1576.     start_time();
  1577.  
  1578. }
  1579.  
  1580. void newdemo_record_render_object(object * obj)
  1581. {
  1582.     stop_time();
  1583.     nd_write_byte(ND_EVENT_RENDER_OBJECT);
  1584.     nd_write_object(obj);
  1585.     start_time();
  1586. }
  1587.  
  1588. void newdemo_record_viewer_object(object * obj)
  1589. {
  1590.     stop_time();
  1591.     nd_write_byte(ND_EVENT_VIEWER_OBJECT);
  1592.     nd_write_object(obj);
  1593.     start_time();
  1594. }
  1595.  
  1596. void newdemo_record_sound( int soundno )    {
  1597.     stop_time();
  1598.     nd_write_byte(ND_EVENT_SOUND);
  1599.     nd_write_int( soundno );
  1600.     start_time();
  1601. }
  1602. //--unused-- void newdemo_record_sound_once( int soundno )  {
  1603. //--unused--    stop_time();
  1604. //--unused--    nd_write_byte( ND_EVENT_SOUND_ONCE );
  1605. //--unused--    nd_write_int( soundno );
  1606. //--unused--    start_time();
  1607. //--unused-- }
  1608. //--unused-- 
  1609.  
  1610. void newdemo_record_sound_3d( int soundno, int angle, int volume )  {
  1611.     stop_time();
  1612.     nd_write_byte( ND_EVENT_SOUND_3D );
  1613.     nd_write_int( soundno );
  1614.     nd_write_int( angle );
  1615.     nd_write_int( volume );
  1616.     start_time();
  1617. }
  1618.  
  1619. void newdemo_record_sound_3d_once( int soundno, int angle, int volume ) {
  1620.     stop_time();
  1621.     nd_write_byte( ND_EVENT_SOUND_3D_ONCE );
  1622.     nd_write_int( soundno );
  1623.     nd_write_int( angle );
  1624.     nd_write_int( volume );
  1625.     start_time();
  1626. }
  1627.  
  1628. void newdemo_record_wall_hit_process( int segnum, int side, int damage, int playernum )
  1629. {
  1630.     stop_time();
  1631. //  segnum = segnum;
  1632. //  side = side;
  1633. //  damage = damage;
  1634. //  playernum = playernum;
  1635.     nd_write_byte( ND_EVENT_WALL_HIT_PROCESS );
  1636.     nd_write_int( segnum );
  1637.     nd_write_int( side );
  1638.     nd_write_int( damage );
  1639.     nd_write_int( playernum );
  1640.     start_time();
  1641. }
  1642.  
  1643. void newdemo_record_trigger( int segnum, int side, int objnum )
  1644. {
  1645.     stop_time();
  1646.     nd_write_byte( ND_EVENT_TRIGGER );
  1647.     nd_write_int( segnum );
  1648.     nd_write_int( side );
  1649.     nd_write_int( objnum );
  1650.     start_time();
  1651. }
  1652.  
  1653. void newdemo_record_hostage_rescued( int hostage_number )   {
  1654.     stop_time();
  1655.     nd_write_byte( ND_EVENT_HOSTAGE_RESCUED );
  1656.     nd_write_int( hostage_number );
  1657.     start_time();
  1658. }
  1659.  
  1660. void newdemo_record_morph_frame(morph_data *md) {
  1661.     stop_time();
  1662.  
  1663.     nd_write_byte( ND_EVENT_MORPH_FRAME );
  1664. #if 0
  1665.     newdemo_write( md->morph_vecs, sizeof(md->morph_vecs), 1 );
  1666.     newdemo_write( md->submodel_active, sizeof(md->submodel_active), 1 );
  1667.     newdemo_write( md->submodel_startpoints, sizeof(md->submodel_startpoints), 1 );
  1668. #endif
  1669.     nd_write_object( md->obj );
  1670.     start_time();
  1671. }
  1672.  
  1673. void newdemo_record_wall_toggle( int segnum, int side ) {
  1674.     stop_time();
  1675.     nd_write_byte( ND_EVENT_WALL_TOGGLE );
  1676.     nd_write_int( segnum );
  1677.     nd_write_int( side );
  1678.     start_time();
  1679. }
  1680.  
  1681. void newdemo_record_control_center_destroyed()
  1682. {
  1683.     stop_time();
  1684.     nd_write_byte( ND_EVENT_CONTROL_CENTER_DESTROYED );
  1685.     nd_write_int( Fuelcen_seconds_left );
  1686.     start_time();
  1687. }
  1688.  
  1689. void newdemo_record_hud_message( char * message )
  1690. {
  1691.     stop_time();
  1692.     nd_write_byte( ND_EVENT_HUD_MESSAGE );
  1693.     nd_write_string(message);
  1694.     start_time();
  1695. }
  1696.  
  1697. void newdemo_record_palette_effect(short r, short g, short b )
  1698. {
  1699.     stop_time();
  1700.     nd_write_byte( ND_EVENT_PALETTE_EFFECT );
  1701.     nd_write_short( r );
  1702.     nd_write_short( g );
  1703.     nd_write_short( b );
  1704.     start_time();
  1705. }
  1706.  
  1707. #ifdef SHAREWARE
  1708. void newdemo_record_player_energy(int energy)
  1709. #else
  1710. void newdemo_record_player_energy(int old_energy, int energy)
  1711. #endif
  1712. {
  1713.     stop_time();
  1714.     nd_write_byte( ND_EVENT_PLAYER_ENERGY );
  1715. #ifndef SHAREWARE
  1716.     nd_write_byte((byte) old_energy);
  1717. #endif
  1718.     nd_write_byte((byte) energy);
  1719.     start_time();
  1720. }
  1721.  
  1722. #ifdef SHAREWARE
  1723. void newdemo_record_player_shields(int shield)
  1724. #else
  1725. void newdemo_record_player_shields(int old_shield, int shield)
  1726. #endif
  1727. {
  1728.     stop_time();
  1729.     nd_write_byte( ND_EVENT_PLAYER_SHIELD );
  1730. #ifndef SHAREWARE
  1731.     nd_write_byte((byte)old_shield);
  1732. #endif
  1733.     nd_write_byte((byte)shield);
  1734.     start_time();
  1735. }
  1736.  
  1737. void newdemo_record_player_flags(uint oflags, uint flags)
  1738. {
  1739.     stop_time();
  1740.     nd_write_byte( ND_EVENT_PLAYER_FLAGS );
  1741.     nd_write_int(((short)oflags << 16) | (short)flags);
  1742.     start_time();
  1743. }
  1744.  
  1745. void newdemo_record_player_weapon(int weapon_type, int weapon_num)
  1746. {
  1747.     stop_time();
  1748.     nd_write_byte( ND_EVENT_PLAYER_WEAPON );
  1749.     nd_write_byte((byte)weapon_type);
  1750.     nd_write_byte((byte)weapon_num);
  1751. #ifndef SHAREWARE
  1752.     if (weapon_type)
  1753.         nd_write_byte((byte)Secondary_weapon);
  1754.     else
  1755.         nd_write_byte((byte)Primary_weapon);
  1756. #endif
  1757.     start_time();
  1758. }
  1759.  
  1760. void newdemo_record_effect_blowup(short segment, int side, vms_vector *pnt)
  1761. {
  1762.     stop_time();
  1763.     nd_write_byte (ND_EVENT_EFFECT_BLOWUP);
  1764.     nd_write_short(segment);
  1765.     nd_write_byte((byte)side);
  1766.     nd_write_vector(pnt);
  1767.     start_time();
  1768. }
  1769.  
  1770. void newdemo_record_homing_distance(fix distance)
  1771. {
  1772.     stop_time();
  1773.     nd_write_byte(ND_EVENT_HOMING_DISTANCE);
  1774.     nd_write_short((short)(distance>>16));
  1775.     start_time();
  1776. }
  1777.  
  1778. void newdemo_record_letterbox(void)
  1779. {
  1780.     stop_time();
  1781.     nd_write_byte(ND_EVENT_LETTERBOX);
  1782.     start_time();
  1783. }
  1784.  
  1785. void newdemo_record_rearview(void)
  1786. {
  1787.     stop_time();
  1788.     nd_write_byte(ND_EVENT_REARVIEW);
  1789.     start_time();
  1790. }
  1791.  
  1792. void newdemo_record_restore_cockpit(void)
  1793. {
  1794.     stop_time();
  1795.     nd_write_byte(ND_EVENT_RESTORE_COCKPIT);
  1796.     start_time();
  1797. }
  1798.  
  1799. void newdemo_record_restore_rearview(void)
  1800. {
  1801.     stop_time();
  1802.     nd_write_byte(ND_EVENT_RESTORE_REARVIEW);
  1803.     start_time();
  1804. }
  1805.  
  1806. void newdemo_record_wall_set_tmap_num1(short seg,ubyte side,short cseg,ubyte cside,short tmap)
  1807. {
  1808.     stop_time();
  1809.     nd_write_byte(ND_EVENT_WALL_SET_TMAP_NUM1);
  1810.     nd_write_short(seg);
  1811.     nd_write_byte(side);
  1812.     nd_write_short(cseg);
  1813.     nd_write_byte(cside);
  1814.     nd_write_short(tmap);
  1815.     start_time();
  1816. }
  1817.  
  1818. void newdemo_record_wall_set_tmap_num2(short seg,ubyte side,short cseg,ubyte cside,short tmap)
  1819. {
  1820.     stop_time();
  1821.     nd_write_byte(ND_EVENT_WALL_SET_TMAP_NUM2);
  1822.     nd_write_short(seg);
  1823.     nd_write_byte(side);
  1824.     nd_write_short(cseg);
  1825.     nd_write_byte(cside);
  1826.     nd_write_short(tmap);
  1827.     start_time();
  1828. }
  1829.  
  1830. void newdemo_record_multi_cloak(int pnum)
  1831. {
  1832.     stop_time();
  1833.     nd_write_byte(ND_EVENT_MULTI_CLOAK);
  1834.     nd_write_byte((byte)pnum);
  1835.     start_time();
  1836. }
  1837.  
  1838. void newdemo_record_multi_decloak(int pnum)
  1839. {
  1840.     stop_time();
  1841.     nd_write_byte(ND_EVENT_MULTI_DECLOAK);
  1842.     nd_write_byte((byte)pnum);
  1843.     start_time();
  1844. }
  1845.  
  1846. #ifndef SHAREWARE
  1847.  
  1848. void newdemo_record_multi_death(int pnum)
  1849. {
  1850.     stop_time();
  1851.     nd_write_byte(ND_EVENT_MULTI_DEATH);
  1852.     nd_write_byte((byte)pnum);
  1853.     start_time();
  1854. }
  1855.  
  1856. void newdemo_record_multi_kill(int pnum, byte kill)
  1857. {
  1858.     stop_time();
  1859.     nd_write_byte(ND_EVENT_MULTI_KILL);
  1860.     nd_write_byte((byte)pnum);
  1861.     nd_write_byte(kill);
  1862.     start_time();
  1863. }
  1864.  
  1865. void newdemo_record_multi_connect(int pnum, int new_player, char *new_callsign)
  1866. {
  1867.     stop_time();
  1868.     nd_write_byte(ND_EVENT_MULTI_CONNECT);
  1869.     nd_write_byte((byte)pnum);
  1870.     nd_write_byte((byte)new_player);
  1871.     if (!new_player) {
  1872.         nd_write_string(Players[pnum].callsign);
  1873.         nd_write_int(Players[pnum].net_killed_total);
  1874.         nd_write_int(Players[pnum].net_kills_total);
  1875.     }
  1876.     nd_write_string(new_callsign);
  1877.     start_time();
  1878. }
  1879.  
  1880. void newdemo_record_multi_reconnect(int pnum)
  1881. {
  1882.     stop_time();
  1883.     nd_write_byte(ND_EVENT_MULTI_RECONNECT);
  1884.     nd_write_byte((byte)pnum);
  1885.     start_time();
  1886. }
  1887.  
  1888. void newdemo_record_multi_disconnect(int pnum)
  1889. {
  1890.     stop_time();
  1891.     nd_write_byte(ND_EVENT_MULTI_DISCONNECT);
  1892.     nd_write_byte((byte)pnum);
  1893.     start_time();
  1894. }
  1895.  
  1896. void newdemo_record_player_score(int score)
  1897. {
  1898.     stop_time();
  1899.     nd_write_byte(ND_EVENT_PLAYER_SCORE);
  1900.     nd_write_int(score);
  1901.     start_time();
  1902. }
  1903.  
  1904. void newdemo_record_multi_score(int pnum, int score)
  1905. {
  1906.     stop_time();
  1907.     nd_write_byte(ND_EVENT_MULTI_SCORE);
  1908.     nd_write_byte((byte)pnum);
  1909.     nd_write_int(score - Players[pnum].score);      // called before score is changed!!!!
  1910.     start_time();
  1911. }
  1912.  
  1913. void newdemo_record_primary_ammo(int old_ammo, int new_ammo)
  1914. {
  1915.     stop_time();
  1916.     nd_write_byte(ND_EVENT_PRIMARY_AMMO);
  1917.     if (old_ammo < 0)
  1918.         nd_write_short((short)new_ammo);
  1919.     else
  1920.         nd_write_short((short)old_ammo);
  1921.     nd_write_short((short)new_ammo);
  1922.     start_time();
  1923. }
  1924.  
  1925. void newdemo_record_secondary_ammo(int old_ammo, int new_ammo)
  1926. {
  1927.     stop_time();
  1928.     nd_write_byte(ND_EVENT_SECONDARY_AMMO);
  1929.     if (old_ammo < 0)
  1930.         nd_write_short((short)new_ammo);
  1931.     else
  1932.         nd_write_short((short)old_ammo);
  1933.     nd_write_short((short)new_ammo);
  1934.     start_time();
  1935. }
  1936.  
  1937. void newdemo_record_door_opening(int segnum, int side)
  1938. {
  1939.     stop_time();
  1940.     nd_write_byte(ND_EVENT_DOOR_OPENING);
  1941.     nd_write_short((short)segnum);
  1942.     nd_write_byte((byte)side);
  1943.     start_time();
  1944. }
  1945.  
  1946. void newdemo_record_laser_level(byte old_level, byte new_level)
  1947. {
  1948.     stop_time();
  1949.     nd_write_byte(ND_EVENT_LASER_LEVEL);
  1950.     nd_write_byte(old_level);
  1951.     nd_write_byte(new_level);
  1952.     start_time();
  1953. }
  1954.  
  1955. #endif
  1956.  
  1957. void newdemo_set_new_level(int level_num)
  1958. {
  1959.     stop_time();
  1960.     nd_write_byte(ND_EVENT_NEW_LEVEL);
  1961.     nd_write_byte((byte)level_num);
  1962.     nd_write_byte((byte)Current_level_num);
  1963.     start_time();
  1964. }
  1965.  
  1966. int newdemo_read_demo_start(int rnd_demo)
  1967. {
  1968.     byte i, version, game_type, laser_level;
  1969.     char c, energy, shield;
  1970.     char text[50], current_mission[9];
  1971.  
  1972.     nd_read_byte(&c);
  1973.     if ((c != ND_EVENT_START_DEMO) || nd_bad_read) {
  1974.         newmenu_item m[1];
  1975.  
  1976.         sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_DEMO_CORRUPT);
  1977.         m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
  1978.         newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
  1979.         return 1;
  1980.     }
  1981.     nd_read_byte(&version);
  1982.     if (version < DEMO_VERSION) {
  1983.         if (!rnd_demo) {
  1984.             newmenu_item m[1];
  1985.             sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_DEMO_OLD);
  1986.             m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
  1987.             newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
  1988.         }
  1989.         return 1;
  1990.     }
  1991.     nd_read_byte(&game_type);
  1992.     if (game_type != DEMO_GAME_TYPE) {
  1993.         newmenu_item m[3];
  1994.  
  1995.         sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_RECORDED);
  1996.         m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
  1997. #ifdef SHAREWARE
  1998.         m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_WITH_REGISTERED;
  1999. #else
  2000.         m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_WITH_SHAREWARE;
  2001. #endif
  2002.         m[ 2].type = NM_TYPE_TEXT; m[ 2].text = TXT_OF_DESCENT;
  2003.     
  2004.         newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
  2005.         return 1;
  2006.     }
  2007.     nd_read_fix(&GameTime);
  2008.     nd_read_int(&Newdemo_game_mode);
  2009.  
  2010. #ifndef NETWORK
  2011.     if (Newdemo_game_mode & GM_MULTI) {
  2012.         nm_messagebox( NULL, 1, "Ok", "can't playback net game\nwith this version of code\n" );
  2013.         return 1;
  2014.     }
  2015. #endif
  2016.  
  2017. #ifdef NETWORK
  2018.     change_playernum_to((Newdemo_game_mode >> 16) & 0x7);
  2019. #ifdef SHAREWARE
  2020.     if (Newdemo_game_mode & GM_TEAM)
  2021.         nd_read_byte(&(Netgame.team_vector));
  2022.  
  2023.     for (i =0 ; i < MAX_PLAYERS; i++) {
  2024.         Players[i].cloak_time = 0;
  2025.         Players[i].invulnerable_time = 0;
  2026.     }
  2027. #else
  2028.     if (Newdemo_game_mode & GM_TEAM) {
  2029.         nd_read_byte(&(Netgame.team_vector));
  2030.         nd_read_string(Netgame.team_name[0]);
  2031.         nd_read_string(Netgame.team_name[1]);
  2032.     }
  2033.     if (Newdemo_game_mode & GM_MULTI) {
  2034.  
  2035.         multi_new_game();
  2036.         nd_read_byte((byte *)&N_players);
  2037.         for (i = 0 ; i < N_players; i++) {
  2038.             Players[i].cloak_time = 0;
  2039.             Players[i].invulnerable_time = 0;
  2040.             nd_read_string(Players[i].callsign);
  2041.             nd_read_byte(&(Players[i].connected));
  2042.  
  2043.             if (Newdemo_game_mode & GM_MULTI_COOP) {
  2044.                 nd_read_int(&(Players[i].score));
  2045.             } else {
  2046.                 nd_read_short((short *)&(Players[i].net_killed_total));
  2047.                 nd_read_short((short *)&(Players[i].net_kills_total));
  2048.             }
  2049.         }
  2050.         Game_mode = Newdemo_game_mode;
  2051.         multi_sort_kill_list();
  2052.         Game_mode = GM_NORMAL;
  2053.     } else
  2054. #endif
  2055.         nd_read_int(&(Players[Player_num].score));      // Note link to above if!
  2056.  
  2057.     for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
  2058.         nd_read_short((short*)&(Players[Player_num].primary_ammo[i]));
  2059.  
  2060.     for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
  2061.             nd_read_short((short*)&(Players[Player_num].secondary_ammo[i]));
  2062.  
  2063.     nd_read_byte(&laser_level);
  2064.     if (laser_level != Players[Player_num].laser_level) {
  2065.         Players[Player_num].laser_level = laser_level;
  2066.         update_laser_weapon_info();
  2067.     }
  2068.  
  2069. // Support for missions
  2070.  
  2071.     nd_read_string(current_mission);
  2072. #ifdef DEST_SAT
  2073.     if (!strcmp(current_mission, ""))
  2074.         strcpy(current_mission, "DESTSAT");
  2075. #endif
  2076.     if (!load_mission_by_name(current_mission)) {
  2077.         newmenu_item m[1];
  2078.  
  2079.         sprintf(text, TXT_NOMISSION4DEMO, current_mission);
  2080.         m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
  2081.         newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
  2082.         return 1;
  2083.     }
  2084.  
  2085. #endif
  2086.  
  2087.     nd_recorded_total = 0;
  2088.     nd_playback_total = 0;
  2089.     nd_read_byte(&energy);
  2090.     nd_read_byte(&shield);
  2091.  
  2092.     nd_read_int((int *)&(Players[Player_num].flags));
  2093.     if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) {
  2094.         Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
  2095.         Newdemo_players_cloaked |= (1 << Player_num);
  2096.     }
  2097.     if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
  2098.         Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
  2099.  
  2100.     nd_read_byte((byte *)&Primary_weapon);
  2101.     nd_read_byte((byte *)&Secondary_weapon);
  2102.  
  2103. // Next bit of code to fix problem that I introduced between 1.0 and 1.1
  2104. // check the next byte -- it _will_ be a load_new_level event.  If it is
  2105. // not, then we must shift all bytes up by one.
  2106.  
  2107. #ifdef SHAREWARE
  2108.     {
  2109.         unsigned char c;
  2110.  
  2111.         c = fgetc(infile);
  2112.         if (c != ND_EVENT_NEW_LEVEL) {
  2113.             int flags;
  2114.  
  2115.             flags = Players[Player_num].flags;
  2116.             energy = shield;
  2117.             shield = (unsigned char)flags;
  2118.             flags = (flags >> 8) & 0x00ffffff;
  2119.             flags |= (Primary_weapon << 24);
  2120.             Primary_weapon = Secondary_weapon;
  2121.             Secondary_weapon = c;
  2122.         } else
  2123.             ungetc(c, infile);
  2124.     }
  2125. #endif
  2126.  
  2127.     Players[Player_num].energy = i2f(energy);
  2128.     Players[Player_num].shields = i2f(shield);
  2129.     return 0;
  2130. }
  2131.  
  2132. void newdemo_pop_ctrlcen_triggers()
  2133. {
  2134.     int anim_num, n, i;
  2135.     int side, cside;
  2136.     segment *seg, *csegp;
  2137.  
  2138.     for (i = 0; i < ControlCenterTriggers.num_links; i++)   {
  2139.         seg = &Segments[ControlCenterTriggers.seg[i]];
  2140.         side = ControlCenterTriggers.side[i];
  2141.         csegp = &Segments[seg->children[side]];
  2142.         cside = find_connect_side(seg, csegp);
  2143.         anim_num = Walls[seg->sides[side].wall_num].clip_num;
  2144.         n = WallAnims[anim_num].num_frames;
  2145.         if (WallAnims[anim_num].flags & WCF_TMAP1)  {
  2146.         seg->sides[side].tmap_num = csegp->sides[cside].tmap_num = WallAnims[anim_num].frames[n-1];
  2147.         } else {
  2148.             seg->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = WallAnims[anim_num].frames[n-1];
  2149.         }
  2150.     }
  2151. }
  2152.  
  2153. #define N_PLAYER_SHIP_TEXTURES 6
  2154.  
  2155.  
  2156. int newdemo_read_frame_information()
  2157. {
  2158.     int done, segnum, side, objnum, soundno, angle, volume, i;
  2159.     object *obj;
  2160.     ubyte c;
  2161.     static byte saved_letter_cockpit;
  2162.     static byte saved_rearview_cockpit;
  2163.  
  2164.     done = 0;
  2165.  
  2166.     if (Newdemo_vcr_state != ND_STATE_PAUSED)
  2167.         for (segnum=0; segnum <= Highest_segment_index; segnum++)
  2168.             Segments[segnum].objects = -1;
  2169.  
  2170.     reset_objects(1);
  2171.     Players[Player_num].homing_object_dist = -F1_0;
  2172.  
  2173.     prev_obj = NULL;
  2174.  
  2175.     while( !done )  {
  2176.         nd_read_byte(&c);
  2177.         if (nd_bad_read) { done = -1; break; }
  2178.  
  2179.         switch( c ) {
  2180.  
  2181.         case ND_EVENT_START_FRAME:  {               // Followed by an integer frame number, then a fix FrameTime
  2182.             short last_frame_length;
  2183.  
  2184.             done=1;
  2185.             nd_read_short(&last_frame_length);
  2186.             nd_read_int(&NewdemoFrameCount);
  2187.             nd_read_int((int *)&nd_recorded_time);
  2188.             if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
  2189.                 nd_recorded_total += nd_recorded_time;
  2190.             NewdemoFrameCount--;
  2191.             if (nd_bad_read) { done = -1; break; }
  2192.             break;
  2193.         }
  2194.  
  2195.         case ND_EVENT_VIEWER_OBJECT:                // Followed by an object structure
  2196.             nd_read_object(Viewer);
  2197.             if (Newdemo_vcr_state != ND_STATE_PAUSED) {
  2198.                 if (nd_bad_read) { done = -1; break; }
  2199.                 segnum = Viewer->segnum;
  2200.                 Viewer->next = Viewer->prev = Viewer->segnum = -1;
  2201.  
  2202. // HACK HACK HACK -- since we have multiple level recording, it can be the case
  2203. // HACK HACK HACK -- that when rewinding the demo, the viewer is in a segment
  2204. // HACK HACK HACK -- that is greater than the highest index of segments.  Bash
  2205. // HACK HACK HACK -- the viewer to segment 0 for bogus view.
  2206.  
  2207.                 if (segnum > Highest_segment_index)
  2208.                     segnum = 0;
  2209.                 obj_link(Viewer-Objects,segnum);
  2210.             }
  2211.             break;
  2212.  
  2213.         case ND_EVENT_RENDER_OBJECT:               // Followed by an object structure
  2214.             objnum = obj_allocate();
  2215.             if (objnum==-1)
  2216.                 break;
  2217.             obj = &Objects[objnum];
  2218.             nd_read_object(obj);
  2219.             if (nd_bad_read) { done = -1; break; }
  2220.             if (Newdemo_vcr_state != ND_STATE_PAUSED) {
  2221.                 segnum = obj->segnum;
  2222.                 obj->next = obj->prev = obj->segnum = -1;
  2223.  
  2224. // HACK HACK HACK -- don't render objects is segments greater than Highest_segment_index
  2225. // HACK HACK HACK -- (see above)
  2226.  
  2227.                 if (segnum > Highest_segment_index)
  2228.                     break;
  2229.  
  2230.                 obj_link(obj-Objects,segnum);
  2231.                 #ifdef NETWORK
  2232.                 if ((obj->type == OBJ_PLAYER) && (Newdemo_game_mode & GM_MULTI)) {
  2233.                     int player;
  2234.  
  2235.                     if (Newdemo_game_mode & GM_TEAM)
  2236.                         player = get_team(obj->id);
  2237.                     else
  2238.                         player = obj->id;
  2239.                     if (player == 0)
  2240.                         break;
  2241.                     player--;
  2242.  
  2243.                     for (i=0;i<N_PLAYER_SHIP_TEXTURES;i++)
  2244.                         multi_player_textures[player][i] = ObjBitmaps[ObjBitmapPtrs[Polygon_models[obj->rtype.pobj_info.model_num].first_texture+i]];
  2245.  
  2246.                     multi_player_textures[player][4] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(player)*2]];
  2247.                     multi_player_textures[player][5] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(player)*2+1]];
  2248.                     obj->rtype.pobj_info.alt_textures = player+1;
  2249.                 }
  2250.                 #endif
  2251.             }
  2252.             break;
  2253.  
  2254.         case ND_EVENT_SOUND:
  2255.             nd_read_int(&soundno);
  2256.             if (nd_bad_read) {done = -1; break; }
  2257.             if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
  2258.                 digi_play_sample( soundno, F1_0 );
  2259.             break;
  2260.  
  2261. //--unused      case ND_EVENT_SOUND_ONCE:
  2262. //--unused          nd_read_int(&soundno);
  2263. //--unused          if (nd_bad_read) { done = -1; break; }
  2264. //--unused          if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
  2265. //--unused              digi_play_sample_once( soundno, F1_0 );
  2266. //--unused          break;
  2267.  
  2268.         case ND_EVENT_SOUND_3D:
  2269.             nd_read_int(&soundno);
  2270.             nd_read_int(&angle);
  2271.             nd_read_int(&volume);
  2272.             if (nd_bad_read) { done = -1; break; }
  2273.             if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
  2274.                 digi_play_sample_3d( soundno, angle, volume, 0 );
  2275.             break;
  2276.  
  2277.         case ND_EVENT_SOUND_3D_ONCE:
  2278.             nd_read_int(&soundno);
  2279.             nd_read_int(&angle);
  2280.             nd_read_int(&volume);
  2281.             if (nd_bad_read) { done = -1; break; }
  2282.             if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
  2283.                 digi_play_sample_3d( soundno, angle, volume, 1 );
  2284.             break;
  2285.  
  2286.         case ND_EVENT_WALL_HIT_PROCESS: {
  2287.             int player, segnum;
  2288.             fix damage;
  2289.  
  2290.             nd_read_int(&segnum);
  2291.             nd_read_int(&side);
  2292.             nd_read_fix(&damage);
  2293.             nd_read_int(&player);
  2294.             if (nd_bad_read) { done = -1; break; }
  2295.             if (Newdemo_vcr_state != ND_STATE_PAUSED)
  2296.                 wall_hit_process(&Segments[segnum], side, damage, player, &(Objects[0]) );
  2297.             break;
  2298.         }
  2299.  
  2300.         case ND_EVENT_TRIGGER:
  2301.             nd_read_int(&segnum);
  2302.             nd_read_int(&side);
  2303.             nd_read_int(&objnum);
  2304.             if (nd_bad_read) { done = -1; break; }
  2305.             if (Newdemo_vcr_state != ND_STATE_PAUSED)
  2306.                 check_trigger(&Segments[segnum], side, objnum);
  2307.             break;
  2308.  
  2309.         case ND_EVENT_HOSTAGE_RESCUED: {
  2310.             int hostage_number;
  2311.  
  2312.             nd_read_int(&hostage_number);
  2313.             if (nd_bad_read) { done = -1; break; }
  2314.             if (Newdemo_vcr_state != ND_STATE_PAUSED)
  2315.                 hostage_rescue( hostage_number );
  2316.             break;
  2317.         }
  2318.  
  2319.         case ND_EVENT_MORPH_FRAME: {
  2320. #if 0
  2321.             morph_data *md;
  2322.  
  2323.             md = &morph_objects[0];
  2324.             if (newdemo_read( md->morph_vecs, sizeof(md->morph_vecs), 1 )!=1) { done=-1; break; }
  2325.             if (newdemo_read( md->submodel_active, sizeof(md->submodel_active), 1 )!=1) { done=-1; break; }
  2326.             if (newdemo_read( md->submodel_startpoints, sizeof(md->submodel_startpoints), 1 )!=1) { done=-1; break; }
  2327. #endif
  2328.             objnum = obj_allocate();
  2329.             if (objnum==-1)
  2330.                 break;
  2331.             obj = &Objects[objnum];
  2332.             nd_read_object(obj);
  2333.             obj->render_type = RT_POLYOBJ;
  2334.             if (Newdemo_vcr_state != ND_STATE_PAUSED) {
  2335.                 if (nd_bad_read) { done = -1; break; }
  2336.                 if (Newdemo_vcr_state != ND_STATE_PAUSED) {
  2337.                     segnum = obj->segnum;
  2338.                     obj->next = obj->prev = obj->segnum = -1;
  2339.                     obj_link(obj-Objects,segnum);
  2340.                 }
  2341.             }
  2342.             break;
  2343.         }
  2344.  
  2345.         case ND_EVENT_WALL_TOGGLE:
  2346.             nd_read_int(&segnum);
  2347.             nd_read_int(&side);
  2348.             if (nd_bad_read) {done = -1; break; }
  2349.             if (Newdemo_vcr_state != ND_STATE_PAUSED)
  2350.                 wall_toggle(&Segments[segnum], side);
  2351.             break;
  2352.  
  2353.         case ND_EVENT_CONTROL_CENTER_DESTROYED:
  2354.             nd_read_int(&Fuelcen_seconds_left);
  2355.             Fuelcen_control_center_destroyed = 1;
  2356.             if (nd_bad_read) { done = -1; break; }
  2357.             if (!Newdemo_cntrlcen_destroyed) {
  2358.                 newdemo_pop_ctrlcen_triggers();
  2359.                 Newdemo_cntrlcen_destroyed = 1;
  2360. //              do_controlcen_destroyed_stuff(NULL);
  2361.             }
  2362.             break;
  2363.  
  2364.         case ND_EVENT_HUD_MESSAGE: {
  2365.             char hud_msg[60];
  2366.  
  2367.             nd_read_string(&(hud_msg[0]));
  2368.             if (nd_bad_read) { done = -1; break; }
  2369.             HUD_init_message( hud_msg );
  2370.             break;
  2371.             }
  2372.  
  2373.         case ND_EVENT_PALETTE_EFFECT: {
  2374.             short r, g, b;
  2375.  
  2376.             nd_read_short(&r);
  2377.             nd_read_short(&g);
  2378.             nd_read_short(&b);
  2379.             if (nd_bad_read) { done = -1; break; }
  2380.             PALETTE_FLASH_SET(r,g,b);
  2381.             break;
  2382.         }
  2383.  
  2384.         case ND_EVENT_PLAYER_ENERGY: {
  2385.             ubyte energy;
  2386. #ifndef SHAREWARE
  2387.             ubyte old_energy;
  2388.  
  2389.             nd_read_byte(&old_energy);
  2390. #endif
  2391.             nd_read_byte(&energy);
  2392.             if (nd_bad_read) {done = -1; break; }
  2393. #ifdef SHAREWARE
  2394.             Players[Player_num].energy = i2f(energy);
  2395. #else
  2396.             if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
  2397.                 Players[Player_num].energy = i2f(energy);
  2398.             } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
  2399.                 if (old_energy != 255)
  2400.                     Players[Player_num].energy = i2f(old_energy);
  2401.             }
  2402. #endif
  2403.             break;
  2404.         }
  2405.  
  2406.         case ND_EVENT_PLAYER_SHIELD: {
  2407.             ubyte shield;
  2408. #ifndef SHAREWARE
  2409.             ubyte old_shield;
  2410.  
  2411.             nd_read_byte(&old_shield);
  2412. #endif
  2413.             nd_read_byte(&shield);
  2414.             if (nd_bad_read) {done = -1; break; }
  2415. #ifdef SHAREWARE
  2416.             Players[Player_num].shields = i2f(shield);
  2417. #else
  2418.             if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
  2419.                 Players[Player_num].shields = i2f(shield);
  2420.             } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
  2421.                 if (old_shield != 255)
  2422.                     Players[Player_num].shields = i2f(old_shield);
  2423.             }
  2424. #endif
  2425.             break;
  2426.         }
  2427.  
  2428.         case ND_EVENT_PLAYER_FLAGS: {
  2429.             uint oflags;
  2430.  
  2431.             nd_read_int((int *)&(Players[Player_num].flags));
  2432.             if (nd_bad_read) {done = -1; break; }
  2433.  
  2434.             oflags = Players[Player_num].flags >> 16;
  2435.             Players[Player_num].flags &= 0xffff;
  2436.  
  2437.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD) && (oflags != 0xffff)) {
  2438.                 if (!(oflags & PLAYER_FLAGS_CLOAKED) && (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
  2439.                     Players[Player_num].cloak_time = 0;
  2440.                     Newdemo_players_cloaked &= ~(1 << Player_num);
  2441.                 }
  2442.                 if ((oflags & PLAYER_FLAGS_CLOAKED) && !(Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
  2443.                     Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
  2444.                     Newdemo_players_cloaked |= (1 << Player_num);
  2445.                 }
  2446.                 if (!(oflags & PLAYER_FLAGS_INVULNERABLE) && (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
  2447.                     Players[Player_num].invulnerable_time = 0;
  2448.                 if ((oflags & PLAYER_FLAGS_INVULNERABLE) && !(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
  2449.                     Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
  2450.                 Players[Player_num].flags = oflags;
  2451.             } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
  2452.                 if (!(oflags & PLAYER_FLAGS_CLOAKED) && (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
  2453.                     Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
  2454.                     Newdemo_players_cloaked |= (1 << Player_num);
  2455.                 }
  2456.                 if ((oflags & PLAYER_FLAGS_CLOAKED) && !(Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
  2457.                     Players[Player_num].cloak_time = 0;
  2458.                     Newdemo_players_cloaked &= ~(1 << Player_num);
  2459.                 }
  2460.                 if (!(oflags & PLAYER_FLAGS_INVULNERABLE) && (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
  2461.                     Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
  2462.                 if ((oflags & PLAYER_FLAGS_INVULNERABLE) && !(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
  2463.                     Players[Player_num].invulnerable_time = 0;
  2464.             }
  2465.             update_laser_weapon_info();     // in case of quad laser change
  2466.             break;
  2467.         }
  2468.  
  2469. #ifdef SHAREWARE
  2470.         case ND_EVENT_PLAYER_WEAPON: {
  2471.             byte weapon_type, weapon_num;
  2472.  
  2473.             nd_read_byte(&weapon_type);
  2474.             nd_read_byte(&weapon_num);
  2475.  
  2476.             if (weapon_type == 0)
  2477.                 Primary_weapon = (int)weapon_num;
  2478.             else
  2479.                 Secondary_weapon = (int)weapon_num;
  2480.  
  2481.             break;
  2482.         }
  2483. #else
  2484.         case ND_EVENT_PLAYER_WEAPON: {
  2485.             byte weapon_type, weapon_num;
  2486.             byte old_weapon;
  2487.  
  2488.             nd_read_byte(&weapon_type);
  2489.             nd_read_byte(&weapon_num);
  2490.             nd_read_byte(&old_weapon);
  2491.             if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
  2492.                 if (weapon_type == 0)
  2493.                     Primary_weapon = (int)weapon_num;
  2494.                 else
  2495.                     Secondary_weapon = (int)weapon_num;
  2496.             } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
  2497.                 if (weapon_type == 0)
  2498.                     Primary_weapon = (int)old_weapon;
  2499.                 else
  2500.                     Secondary_weapon = (int)old_weapon;
  2501.             }
  2502.             break;
  2503.         }
  2504. #endif
  2505.  
  2506.  
  2507.         case ND_EVENT_EFFECT_BLOWUP: {
  2508.             short segnum;
  2509.             byte side;
  2510.             vms_vector pnt;
  2511.  
  2512.             nd_read_short(&segnum);
  2513.             nd_read_byte(&side);
  2514.             nd_read_vector(&pnt);
  2515.             if (Newdemo_vcr_state != ND_STATE_PAUSED)
  2516.                 check_effect_blowup(&(Segments[segnum]), side, &pnt);
  2517.             break;
  2518.         }
  2519.  
  2520.         case ND_EVENT_HOMING_DISTANCE: {
  2521.             short distance;
  2522.  
  2523.             nd_read_short(&distance);
  2524.             Players[Player_num].homing_object_dist = i2f((int)(distance << 16));
  2525.             break;
  2526.         }
  2527.  
  2528.         case ND_EVENT_LETTERBOX:
  2529.             if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
  2530.                 saved_letter_cockpit = Cockpit_mode;
  2531.                 select_cockpit(CM_LETTERBOX);
  2532.             } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
  2533.                 select_cockpit(saved_letter_cockpit);
  2534.             break;
  2535.  
  2536.         case ND_EVENT_REARVIEW:
  2537.             if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
  2538.                 saved_rearview_cockpit = Cockpit_mode;
  2539.                 if (Cockpit_mode == CM_FULL_COCKPIT)
  2540.                     select_cockpit(CM_REAR_VIEW);
  2541.                 Rear_view=1;
  2542.             } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
  2543.                 if (saved_rearview_cockpit == CM_REAR_VIEW)     // hack to be sure we get a good cockpit on restore
  2544.                     saved_rearview_cockpit = CM_FULL_COCKPIT;
  2545.                 select_cockpit(saved_rearview_cockpit);
  2546.                 Rear_view=0;
  2547.             }
  2548.             break;
  2549.  
  2550.         case ND_EVENT_RESTORE_COCKPIT:
  2551.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
  2552.                 saved_letter_cockpit = Cockpit_mode;
  2553.                 select_cockpit(CM_LETTERBOX);
  2554.             } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
  2555.                 select_cockpit(saved_letter_cockpit);
  2556.             break;
  2557.  
  2558.  
  2559.         case ND_EVENT_RESTORE_REARVIEW:
  2560.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
  2561.                 saved_rearview_cockpit = Cockpit_mode;
  2562.                 if (Cockpit_mode == CM_FULL_COCKPIT)
  2563.                     select_cockpit(CM_REAR_VIEW);
  2564.                 Rear_view=1;
  2565.             } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
  2566.                 if (saved_rearview_cockpit == CM_REAR_VIEW)     // hack to be sure we get a good cockpit on restore
  2567.                     saved_rearview_cockpit = CM_FULL_COCKPIT;
  2568.                 select_cockpit(saved_rearview_cockpit);
  2569.                 Rear_view=0;
  2570.             }
  2571.             break;
  2572.  
  2573.  
  2574.         case ND_EVENT_WALL_SET_TMAP_NUM1:   {
  2575.             short seg, cseg, tmap;
  2576.             ubyte side,cside;
  2577.  
  2578.             nd_read_short(&seg);
  2579.             nd_read_byte(&side);
  2580.             nd_read_short(&cseg);
  2581.             nd_read_byte(&cside);
  2582.             nd_read_short( &tmap );
  2583.             if ((Newdemo_vcr_state != ND_STATE_PAUSED) && (Newdemo_vcr_state != ND_STATE_REWINDING) && (Newdemo_vcr_state != ND_STATE_ONEFRAMEBACKWARD))
  2584.                 Segments[seg].sides[side].tmap_num = Segments[cseg].sides[cside].tmap_num = tmap;
  2585.             break;
  2586.         }
  2587.  
  2588.         case ND_EVENT_WALL_SET_TMAP_NUM2:   {
  2589.             short seg, cseg, tmap;
  2590.             ubyte side,cside;
  2591.  
  2592.             nd_read_short(&seg);
  2593.             nd_read_byte(&side);
  2594.             nd_read_short(&cseg);
  2595.             nd_read_byte(&cside);
  2596.             nd_read_short( &tmap );
  2597.             if ((Newdemo_vcr_state != ND_STATE_PAUSED) && (Newdemo_vcr_state != ND_STATE_REWINDING) && (Newdemo_vcr_state != ND_STATE_ONEFRAMEBACKWARD)) {
  2598.                 Assert(tmap!=0 && Segments[seg].sides[side].tmap_num2!=0);
  2599.                 Segments[seg].sides[side].tmap_num2 = Segments[cseg].sides[cside].tmap_num2 = tmap;
  2600.             }
  2601.             break;
  2602.         }
  2603.  
  2604.         case ND_EVENT_MULTI_CLOAK: {
  2605.             byte pnum;
  2606.  
  2607.             nd_read_byte(&pnum);
  2608.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
  2609.                 Players[pnum].flags &= ~PLAYER_FLAGS_CLOAKED;
  2610.                 Players[pnum].cloak_time = 0;
  2611.                 Newdemo_players_cloaked &= ~(1 << pnum);
  2612.             } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
  2613.                 Players[pnum].flags |= PLAYER_FLAGS_CLOAKED;
  2614.                 Players[pnum].cloak_time = GameTime  - (CLOAK_TIME_MAX / 2);
  2615.                 Newdemo_players_cloaked |= (1 << pnum);
  2616.             }
  2617.             break;
  2618.         }
  2619.  
  2620.         case ND_EVENT_MULTI_DECLOAK: {
  2621.             byte pnum;
  2622.  
  2623.             nd_read_byte(&pnum);
  2624.  
  2625.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
  2626.                 Players[pnum].flags |= PLAYER_FLAGS_CLOAKED;
  2627.                 Players[pnum].cloak_time = GameTime  - (CLOAK_TIME_MAX / 2);
  2628.                 Newdemo_players_cloaked |= (1 << pnum);
  2629.             } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
  2630.                 Players[pnum].flags &= ~PLAYER_FLAGS_CLOAKED;
  2631.                 Players[pnum].cloak_time = 0;
  2632.                 Newdemo_players_cloaked &= ~(1 << pnum);
  2633.             }
  2634.             break;
  2635.         }
  2636.  
  2637. #ifndef SHAREWARE
  2638.         case ND_EVENT_MULTI_DEATH: {
  2639.             byte pnum;
  2640.  
  2641.             nd_read_byte(&pnum);
  2642.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
  2643.                 Players[pnum].net_killed_total--;
  2644.             else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
  2645.                 Players[pnum].net_killed_total++;
  2646.             break;
  2647.         }
  2648.  
  2649.         #ifdef NETWORK  
  2650.         case ND_EVENT_MULTI_KILL: {
  2651.             byte pnum, kill;
  2652.  
  2653.             nd_read_byte(&pnum);
  2654.             nd_read_byte(&kill);
  2655.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
  2656.                 Players[pnum].net_kills_total -= kill;
  2657.                 if (Newdemo_game_mode & GM_TEAM)
  2658.                     team_kills[get_team(pnum)] -= kill;
  2659.             } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
  2660.                 Players[pnum].net_kills_total += kill;
  2661.                 if (Newdemo_game_mode & GM_TEAM)
  2662.                     team_kills[get_team(pnum)] += kill;
  2663.             }
  2664.             Game_mode = Newdemo_game_mode;
  2665.             multi_sort_kill_list();
  2666.             Game_mode = GM_NORMAL;
  2667.             break;
  2668.         }
  2669.         
  2670.         case ND_EVENT_MULTI_CONNECT: {
  2671.             byte pnum, new_player;
  2672.             int killed_total, kills_total;
  2673.             char new_callsign[CALLSIGN_LEN+1], old_callsign[CALLSIGN_LEN+1];
  2674.  
  2675.             nd_read_byte(&pnum);
  2676.             nd_read_byte(&new_player);
  2677.             if (!new_player) {
  2678.                 nd_read_string(old_callsign);
  2679.                 nd_read_int(&killed_total);
  2680.                 nd_read_int(&kills_total);
  2681.             }
  2682.             nd_read_string(new_callsign);
  2683.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
  2684.                 Players[pnum].connected = 0;
  2685.                 if (!new_player) {
  2686.                     memcpy(Players[pnum].callsign, old_callsign, CALLSIGN_LEN+1);
  2687.                     Players[pnum].net_killed_total = killed_total;
  2688.                     Players[pnum].net_kills_total = kills_total;
  2689.                 } else {
  2690.                     N_players--;
  2691.                 }
  2692.             } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
  2693.                 Players[pnum].connected = 1;
  2694.                 Players[pnum].net_kills_total = 0;
  2695.                 Players[pnum].net_killed_total = 0;
  2696.                 memcpy(Players[pnum].callsign, new_callsign, CALLSIGN_LEN+1);
  2697.                 if (new_player)
  2698.                     N_players++;
  2699.             }
  2700.             break;
  2701.         }
  2702.  
  2703.         case ND_EVENT_MULTI_RECONNECT: {
  2704.             byte pnum;
  2705.  
  2706.             nd_read_byte(&pnum);
  2707.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
  2708.                 Players[pnum].connected = 0;
  2709.             else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
  2710.                 Players[pnum].connected = 1;
  2711.             break;
  2712.         }
  2713.  
  2714.         case ND_EVENT_MULTI_DISCONNECT: {
  2715.             byte pnum;
  2716.  
  2717.             nd_read_byte(&pnum);
  2718.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
  2719.                 Players[pnum].connected = 1;
  2720.             else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
  2721.                 Players[pnum].connected = 0;
  2722.             break;
  2723.         }
  2724.  
  2725.         case ND_EVENT_MULTI_SCORE: {
  2726.             int score;
  2727.             byte pnum;
  2728.  
  2729.             nd_read_byte(&pnum);
  2730.             nd_read_int(&score);
  2731.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
  2732.                 Players[pnum].score -= score;
  2733.             else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
  2734.                 Players[pnum].score += score;
  2735.             Game_mode = Newdemo_game_mode;
  2736.             multi_sort_kill_list();
  2737.             Game_mode = GM_NORMAL;
  2738.             break;
  2739.         }
  2740.         #endif
  2741.  
  2742.         case ND_EVENT_PLAYER_SCORE: {
  2743.             int score;
  2744.  
  2745.             nd_read_int(&score);
  2746.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
  2747.                 Players[Player_num].score -= score;
  2748.             else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
  2749.                 Players[Player_num].score += score;
  2750.             break;
  2751.         }
  2752.  
  2753.  
  2754.         case ND_EVENT_PRIMARY_AMMO: {
  2755.             short old_ammo, new_ammo;
  2756.  
  2757.             nd_read_short(&old_ammo);
  2758.             nd_read_short(&new_ammo);
  2759.  
  2760.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
  2761.                 Players[Player_num].primary_ammo[Primary_weapon] = old_ammo;
  2762.             else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
  2763.                 Players[Player_num].primary_ammo[Primary_weapon] = new_ammo;
  2764.             break;
  2765.         }
  2766.  
  2767.         case ND_EVENT_SECONDARY_AMMO: {
  2768.             short old_ammo, new_ammo;
  2769.  
  2770.             nd_read_short(&old_ammo);
  2771.             nd_read_short(&new_ammo);
  2772.  
  2773.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
  2774.                 Players[Player_num].secondary_ammo[Secondary_weapon] = old_ammo;
  2775.             else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
  2776.                 Players[Player_num].secondary_ammo[Secondary_weapon] = new_ammo;
  2777.             break;
  2778.         }
  2779.  
  2780.         case ND_EVENT_DOOR_OPENING: {
  2781.             short segnum;
  2782.             byte side;
  2783.  
  2784.             nd_read_short(&segnum);
  2785.             nd_read_byte(&side);
  2786.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
  2787.                 int anim_num;
  2788.                 int cside;
  2789.                 segment *segp, *csegp;
  2790.  
  2791.                 segp = &Segments[segnum];
  2792.                 csegp = &Segments[segp->children[side]];
  2793.                 cside = find_connect_side(segp, csegp);
  2794.                 anim_num = Walls[segp->sides[side].wall_num].clip_num;
  2795.  
  2796.                 if (WallAnims[anim_num].flags & WCF_TMAP1)  {
  2797.                     segp->sides[side].tmap_num = csegp->sides[cside].tmap_num = WallAnims[anim_num].frames[0];
  2798.                 } else  {
  2799.                     segp->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = WallAnims[anim_num].frames[0];
  2800.                 }
  2801.             }
  2802.             break;
  2803.         }
  2804.  
  2805.         case ND_EVENT_LASER_LEVEL: {
  2806.             byte old_level, new_level;
  2807.  
  2808.             nd_read_byte(&old_level);
  2809.             nd_read_byte(&new_level);
  2810.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
  2811.                 Players[Player_num].laser_level = old_level;
  2812.                 update_laser_weapon_info();
  2813.             } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
  2814.                 Players[Player_num].laser_level = new_level;
  2815.                 update_laser_weapon_info();
  2816.             }
  2817.             break;
  2818.         }
  2819.  
  2820. #endif
  2821.  
  2822.         case ND_EVENT_NEW_LEVEL:    {
  2823.             byte new_level, old_level, loaded_level;
  2824.  
  2825.             nd_read_byte (&new_level);
  2826.             nd_read_byte (&old_level);
  2827.             if (Newdemo_vcr_state == ND_STATE_PAUSED)
  2828.                 break;
  2829.  
  2830.             stop_time();
  2831.             if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
  2832.                 loaded_level = old_level;
  2833.             else {
  2834.                 loaded_level = new_level;
  2835.                 for (i = 0; i < MAX_PLAYERS; i++) {
  2836.                     Players[i].cloak_time = 0;
  2837.                     Players[i].flags &= ~PLAYER_FLAGS_CLOAKED;
  2838.                 }
  2839.             }
  2840. #ifdef DEST_SAT
  2841.             if ( (loaded_level < Last_secret_level) || (loaded_level > Last_level - 1) ) {
  2842.                 newmenu_item m[1];
  2843.  
  2844.                 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_NO_DESTSAT_LVL;
  2845.                 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
  2846.                 return -1;
  2847.             }
  2848. #else
  2849.             if ((loaded_level < Last_secret_level) || (loaded_level > Last_level)) {
  2850.                 newmenu_item m[3];
  2851.  
  2852.                 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_CANT_PLAYBACK;
  2853.                 m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_LEVEL_CANT_LOAD;
  2854.                 m[ 2].type = NM_TYPE_TEXT; m[ 2].text = TXT_DEMO_OLD_CORRUPT;
  2855.                 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
  2856.                 return -1;
  2857.             }
  2858. #endif
  2859.             LoadLevel((int)loaded_level);
  2860.             piggy_load_level_data();
  2861.             Newdemo_cntrlcen_destroyed = 0;
  2862. // so says Rob H.!!!            if (Newdemo_game_mode & GM_MULTI) {
  2863. // so says Rob H.!!!                for (i = 0; i < Num_walls; i++) {
  2864. // so says Rob H.!!!                    if (Walls[i].type == WALL_BLASTABLE) 
  2865. // so says Rob H.!!!                    {
  2866. // so says Rob H.!!!                        int a, n;
  2867. // so says Rob H.!!!                        int side;
  2868. // so says Rob H.!!!                        segment *seg;
  2869. // so says Rob H.!!!
  2870. // so says Rob H.!!!                        seg = &Segments[Walls[i].segnum];
  2871. // so says Rob H.!!!                        side = Walls[i].sidenum;
  2872. // so says Rob H.!!!                        a = Walls[i].clip_num;
  2873. // so says Rob H.!!!                        n = WallAnims[a].num_frames;
  2874. // so says Rob H.!!!                        seg->sides[side].tmap_num = WallAnims[a].frames[n-1];
  2875. // so says Rob H.!!!                        Walls[i].flags |= WALL_BLASTED;
  2876. // so says Rob H.!!!                    }
  2877. // so says Rob H.!!!                }
  2878. // so says Rob H.!!!            }
  2879.  
  2880.             reset_palette_add();                    // get palette back to normal
  2881.             start_time();
  2882.             break;
  2883.         }
  2884.  
  2885.         case ND_EVENT_EOF: {
  2886.             done=-1;
  2887.             fseek(infile, -1, SEEK_CUR);                    // get back to the EOF marker
  2888.             Newdemo_at_eof = 1;
  2889.             NewdemoFrameCount++;
  2890.             break;
  2891.         }
  2892.  
  2893.         default:
  2894.             Int3();
  2895.         }
  2896.     }
  2897.     if (nd_bad_read) {
  2898.         newmenu_item m[2];
  2899.  
  2900.         m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_DEMO_ERR_READING;
  2901.         m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_DEMO_OLD_CORRUPT;
  2902.         newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
  2903.     }
  2904.  
  2905.     return done;
  2906. }
  2907.  
  2908. void newdemo_goto_beginning()
  2909. {
  2910.     if (NewdemoFrameCount == 0)
  2911.         return;
  2912.     fseek(infile, 0, SEEK_SET);
  2913.     Newdemo_vcr_state = ND_STATE_PLAYBACK;
  2914.     if (newdemo_read_demo_start(0))
  2915.         newdemo_stop_playback();
  2916.     if (newdemo_read_frame_information() == -1)
  2917.         newdemo_stop_playback();
  2918.     if (newdemo_read_frame_information() == -1)
  2919.         newdemo_stop_playback();
  2920.     Newdemo_vcr_state = ND_STATE_PAUSED;
  2921.     Newdemo_at_eof = 0;
  2922. }
  2923.  
  2924. #ifdef SHAREWARE
  2925. void newdemo_goto_end()
  2926. {
  2927.     short frame_length;
  2928.     byte level;
  2929.     int i;
  2930.  
  2931.     fseek(infile, -2, SEEK_END);
  2932.     nd_read_byte(&level);
  2933.     if ((level < LAST_SECRET_LEVEL) || (level > LAST_LEVEL)) {
  2934.         newmenu_item m[3];
  2935.  
  2936.         m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_CANT_PLAYBACK;
  2937.         m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_LEVEL_CANT_LOAD;
  2938.         m[ 2].type = NM_TYPE_TEXT; m[ 2].text = TXT_DEMO_OLD_CORRUPT;
  2939.         newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
  2940.         newdemo_stop_playback();
  2941.         return;
  2942.     }
  2943.     if (level != Current_level_num) {
  2944.         LoadLevel(level);
  2945.         piggy_load_level_data();
  2946.     }
  2947.     if (Newdemo_game_mode & GM_MULTI) {
  2948.         fseek(infile, -10, SEEK_END);
  2949.         nd_read_byte(&Newdemo_players_cloaked);
  2950.         for (i = 0; i < MAX_PLAYERS; i++) {
  2951.             if ((1 << i) & Newdemo_players_cloaked)
  2952.                 Players[i].flags |= PLAYER_FLAGS_CLOAKED;
  2953.                 Players[i].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
  2954.         }
  2955.     }
  2956.     fseek(infile, -12, SEEK_END);
  2957.     nd_read_short(&frame_length);
  2958.     fseek(infile, -frame_length, SEEK_CUR);
  2959.     nd_read_int(&NewdemoFrameCount);                // get the frame count
  2960.     NewdemoFrameCount--;
  2961.     fseek(infile, 4, SEEK_CUR);
  2962.     newdemo_read_frame_information();           // then the frame information
  2963.     Newdemo_vcr_state = ND_STATE_PAUSED;
  2964.     return;
  2965. }
  2966. #else
  2967. void newdemo_goto_end()
  2968. {
  2969.     short frame_length, byte_count, bshort;
  2970.     byte level, bbyte, laser_level;
  2971.     ubyte energy, shield;
  2972.     int i, loc, bint;
  2973.  
  2974.     fseek(infile, -2, SEEK_END);
  2975.     nd_read_byte(&level);
  2976.  
  2977.     if ((level < Last_secret_level) || (level > Last_level)) {
  2978.         newmenu_item m[3];
  2979.  
  2980.         m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_CANT_PLAYBACK;
  2981.         m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_LEVEL_CANT_LOAD;
  2982.         m[ 2].type = NM_TYPE_TEXT; m[ 2].text = TXT_DEMO_OLD_CORRUPT;
  2983.         newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
  2984.         newdemo_stop_playback();
  2985.         return;
  2986.     }
  2987.     if (level != Current_level_num) {
  2988.         LoadLevel(level);
  2989.         piggy_load_level_data();
  2990.     }
  2991.     fseek(infile, -4, SEEK_END);
  2992.     nd_read_short(&byte_count);
  2993.     fseek(infile, -2 - byte_count, SEEK_CUR);
  2994.  
  2995.     nd_read_short(&frame_length);
  2996.     loc = ftell(infile);
  2997.     if (Newdemo_game_mode & GM_MULTI)
  2998.         nd_read_byte(&Newdemo_players_cloaked);
  2999.     else
  3000.         nd_read_byte(&bbyte);
  3001.     nd_read_byte(&bbyte);
  3002.     nd_read_short(&bshort);
  3003.     nd_read_int(&bint);
  3004.     
  3005.     nd_read_byte(&energy);
  3006.     nd_read_byte(&shield);
  3007.     Players[Player_num].energy = i2f(energy);
  3008.     Players[Player_num].shields = i2f(shield);
  3009.     nd_read_int((int *)&(Players[Player_num].flags));
  3010.     if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) {
  3011.         Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
  3012.         Newdemo_players_cloaked |= (1 << Player_num);
  3013.     }
  3014.     if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
  3015.         Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
  3016.     nd_read_byte((byte *)&Primary_weapon);
  3017.     nd_read_byte((byte *)&Secondary_weapon);
  3018.     for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
  3019.         nd_read_short((short *)&(Players[Player_num].primary_ammo[i])); 
  3020.     for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
  3021.         nd_read_short((short *)&(Players[Player_num].secondary_ammo[i]));   
  3022.     nd_read_byte(&laser_level);
  3023.     if (laser_level != Players[Player_num].laser_level) {
  3024.         Players[Player_num].laser_level = laser_level;
  3025.         update_laser_weapon_info();
  3026.     }
  3027.  
  3028.     if (Newdemo_game_mode & GM_MULTI) {
  3029.         nd_read_byte((byte *)&N_players);
  3030.         for (i = 0; i < N_players; i++) {
  3031.             nd_read_string(Players[i].callsign);
  3032.             nd_read_byte(&(Players[i].connected));
  3033.             if (Newdemo_game_mode & GM_MULTI_COOP) {
  3034.                 nd_read_int(&(Players[i].score));
  3035.             } else {
  3036.                 nd_read_short((short *)&(Players[i].net_killed_total));
  3037.                 nd_read_short((short *)&(Players[i].net_kills_total));
  3038.             }
  3039.         }
  3040.     } else {
  3041.         nd_read_int(&(Players[Player_num].score));
  3042.     }
  3043.  
  3044.     fseek(infile, loc, SEEK_SET);
  3045.     fseek(infile, -frame_length, SEEK_CUR);
  3046.     nd_read_int(&NewdemoFrameCount);                // get the frame count
  3047.     NewdemoFrameCount--;
  3048.     fseek(infile, 4, SEEK_CUR);
  3049.     Newdemo_vcr_state = ND_STATE_PLAYBACK;
  3050.     newdemo_read_frame_information();           // then the frame information
  3051.     Newdemo_vcr_state = ND_STATE_PAUSED;
  3052.     return;
  3053. }
  3054. #endif
  3055.  
  3056. void newdemo_back_frames(int frames)
  3057. {
  3058.     short last_frame_length;
  3059.     int i;
  3060.  
  3061.     for (i = 0; i < frames; i++)
  3062.     {
  3063.         fseek(infile, -10, SEEK_CUR);
  3064.         nd_read_short(&last_frame_length);          
  3065.         fseek(infile, 8 - last_frame_length, SEEK_CUR);
  3066.  
  3067.         if (!Newdemo_at_eof && newdemo_read_frame_information() == -1) {
  3068.             newdemo_stop_playback();
  3069.             return;
  3070.         }
  3071.         if (Newdemo_at_eof)
  3072.             Newdemo_at_eof = 0;
  3073.  
  3074.         fseek(infile, -10, SEEK_CUR);
  3075.         nd_read_short(&last_frame_length);          
  3076.         fseek(infile, 8 - last_frame_length, SEEK_CUR);
  3077.     }
  3078.  
  3079. }
  3080.  
  3081. /*
  3082.  *  routine to interpolate the viewer position.  the current position is
  3083.  *  stored in the Viewer object.  Save this position, and read the next
  3084.  *  frame to get all objects read in.  Calculate the delta playback and
  3085.  *  the delta recording frame times between the two frames, then intepolate
  3086.  *  the viewers position accordingly.  nd_recorded_time is the time that it
  3087.  *  took the recording to render the frame that we are currently looking
  3088.  *  at.
  3089. */
  3090.  
  3091. void interpolate_frame(fix d_play, fix d_recorded)
  3092. {
  3093.     int i, j, num_cur_objs;
  3094.     fix factor;
  3095.     object *cur_objs;
  3096.  
  3097.     factor = fixdiv(d_play, d_recorded);
  3098.     if (factor > F1_0)
  3099.         factor = F1_0;
  3100.  
  3101.     num_cur_objs = Highest_object_index;
  3102.     cur_objs = (object *)malloc(sizeof(object) * (num_cur_objs + 1));
  3103.     if (cur_objs == NULL) {
  3104.         mprintf((0,"Couldn't get %d bytes for cur_objs in interpolate_frame\n", sizeof(object) * num_cur_objs));
  3105.         Int3();
  3106.         return;
  3107.     }
  3108.     for (i = 0; i <= num_cur_objs; i++)
  3109.         memcpy(&(cur_objs[i]), &(Objects[i]), sizeof(object));
  3110.  
  3111.     Newdemo_vcr_state = ND_STATE_PAUSED;
  3112.     if (newdemo_read_frame_information() == -1) {
  3113.         free(cur_objs);
  3114.         newdemo_stop_playback();
  3115.         return;
  3116.     }
  3117.  
  3118.     for (i = 0; i <= num_cur_objs; i++) {
  3119.         for (j = 0; j <= Highest_object_index; j++) {
  3120.             if (cur_objs[i].signature == Objects[j].signature) {
  3121.                 ubyte render_type = cur_objs[i].render_type;
  3122.                 // fix delta_p, delta_h, delta_b;
  3123.                 fix delta_x, delta_y, delta_z;
  3124.                 // vms_angvec cur_angles, dest_angles;
  3125.  
  3126. //  Extract the angles from the object orientation matrix.
  3127. //  Some of this code taken from ai_turn_towards_vector
  3128. //  Don't do the interpolation on certain render types which don't use an orientation matrix
  3129.  
  3130.                 if (!((render_type == RT_LASER) || (render_type == RT_FIREBALL) || (render_type == RT_POWERUP))) {
  3131.  
  3132. vms_vector  fvec1, fvec2, rvec1, rvec2;
  3133. fix         mag1;
  3134.  
  3135. fvec1 = cur_objs[i].orient.fvec;
  3136. vm_vec_scale(&fvec1, F1_0-factor);
  3137. fvec2 = Objects[j].orient.fvec;
  3138. vm_vec_scale(&fvec2, factor);
  3139. vm_vec_add2(&fvec1, &fvec2);
  3140. mag1 = vm_vec_normalize_quick(&fvec1);
  3141. if (mag1 > F1_0/256) {
  3142.     rvec1 = cur_objs[i].orient.rvec;
  3143.     vm_vec_scale(&rvec1, F1_0-factor);
  3144.     rvec2 = Objects[j].orient.rvec;
  3145.     vm_vec_scale(&rvec2, factor);
  3146.     vm_vec_add2(&rvec1, &rvec2);
  3147.     vm_vec_normalize_quick(&rvec1); //  Note: Doesn't matter if this is null, if null, vm_vector_2_matrix will just use fvec1
  3148.     vm_vector_2_matrix(&cur_objs[i].orient, &fvec1, NULL, &rvec1);
  3149. }
  3150.  
  3151. //--old new way --  vms_vector  fvec1, fvec2, rvec1, rvec2;
  3152. //--old new way --
  3153. //--old new way --  fvec1 = cur_objs[i].orient.fvec;
  3154. //--old new way --  vm_vec_scale(&fvec1, F1_0-factor);
  3155. //--old new way --  fvec2 = Objects[j].orient.fvec;
  3156. //--old new way --  vm_vec_scale(&fvec2, factor);
  3157. //--old new way --  vm_vec_add2(&fvec1, &fvec2);
  3158. //--old new way --  vm_vec_normalize_quick(&fvec1);
  3159. //--old new way --
  3160. //--old new way --  rvec1 = cur_objs[i].orient.rvec;
  3161. //--old new way --  vm_vec_scale(&rvec1, F1_0-factor);
  3162. //--old new way --  rvec2 = Objects[j].orient.rvec;
  3163. //--old new way --  vm_vec_scale(&rvec2, factor);
  3164. //--old new way --  vm_vec_add2(&rvec1, &rvec2);
  3165. //--old new way --  vm_vec_normalize_quick(&rvec1);
  3166. //--old new way --
  3167. //--old new way --  vm_vector_2_matrix(&cur_objs[i].orient, &fvec1, NULL, &rvec1);
  3168.  
  3169. // -- old fashioned way --                  vm_extract_angles_matrix(&cur_angles, &(cur_objs[i].orient));
  3170. // -- old fashioned way --                  vm_extract_angles_matrix(&dest_angles, &(Objects[j].orient));
  3171. // -- old fashioned way --
  3172. // -- old fashioned way --                  delta_p = (dest_angles.p - cur_angles.p);
  3173. // -- old fashioned way --                  delta_h = (dest_angles.h - cur_angles.h);
  3174. // -- old fashioned way --                  delta_b = (dest_angles.b - cur_angles.b);
  3175. // -- old fashioned way --
  3176. // -- old fashioned way --                  if (delta_p != 0) {
  3177. // -- old fashioned way --                      if (delta_p > F1_0/2) delta_p = dest_angles.p - cur_angles.p - F1_0;
  3178. // -- old fashioned way --                      if (delta_p < -F1_0/2) delta_p = dest_angles.p - cur_angles.p + F1_0;
  3179. // -- old fashioned way --                      delta_p = fixmul(delta_p, factor);
  3180. // -- old fashioned way --                      cur_angles.p += delta_p;
  3181. // -- old fashioned way --                  }
  3182. // -- old fashioned way --                  if (delta_h != 0) {
  3183. // -- old fashioned way --                      if (delta_h > F1_0/2) delta_h = dest_angles.h - cur_angles.h - F1_0;
  3184. // -- old fashioned way --                      if (delta_h < -F1_0/2) delta_h = dest_angles.h - cur_angles.h + F1_0;
  3185. // -- old fashioned way --                      delta_h = fixmul(delta_h, factor);
  3186. // -- old fashioned way --                      cur_angles.h += delta_h;
  3187. // -- old fashioned way --                  }
  3188. // -- old fashioned way --                  if (delta_b != 0) {
  3189. // -- old fashioned way --                      if (delta_b > F1_0/2) delta_b = dest_angles.b - cur_angles.b - F1_0;
  3190. // -- old fashioned way --                      if (delta_b < -F1_0/2) delta_b = dest_angles.b - cur_angles.b + F1_0;
  3191. // -- old fashioned way --                      delta_b = fixmul(delta_b, factor);
  3192. // -- old fashioned way --                      cur_angles.b += delta_b;
  3193. // -- old fashioned way --                  }
  3194.                 }
  3195.  
  3196. // Interpolate the object position.  This is just straight linear
  3197. // interpolation.
  3198.  
  3199.                 delta_x = Objects[j].pos.x - cur_objs[i].pos.x;
  3200.                 delta_y = Objects[j].pos.y - cur_objs[i].pos.y;
  3201.                 delta_z = Objects[j].pos.z - cur_objs[i].pos.z;
  3202.  
  3203.                 delta_x = fixmul(delta_x, factor);
  3204.                 delta_y = fixmul(delta_y, factor);
  3205.                 delta_z = fixmul(delta_z, factor);
  3206.  
  3207.                 cur_objs[i].pos.x += delta_x;
  3208.                 cur_objs[i].pos.y += delta_y;
  3209.                 cur_objs[i].pos.z += delta_z;
  3210.     
  3211. // -- old fashioned way --// stuff the new angles back into the object structure
  3212. // -- old fashioned way --              vm_angles_2_matrix(&(cur_objs[i].orient), &cur_angles);
  3213.             }
  3214.         }
  3215.     }
  3216.  
  3217. // get back to original position in the demo file.  Reread the current
  3218. // frame information again to reset all of the object stuff not covered
  3219. // with Highest_object_index and the object array (previously rendered
  3220. // objects, etc....)
  3221.  
  3222.     newdemo_back_frames(1);
  3223.     newdemo_back_frames(1);
  3224.     if (newdemo_read_frame_information() == -1)
  3225.         newdemo_stop_playback();
  3226.     Newdemo_vcr_state = ND_STATE_PLAYBACK;
  3227.  
  3228.     for (i = 0; i <= num_cur_objs; i++)
  3229.         memcpy(&(Objects[i]), &(cur_objs[i]), sizeof(object));
  3230.     Highest_object_index = num_cur_objs;
  3231.     free(cur_objs);
  3232. }
  3233.  
  3234. void newdemo_playback_one_frame()
  3235. {
  3236.     int frames_back, i, level;
  3237.     static fix base_interpol_time = 0;
  3238.     static fix d_recorded = 0;
  3239.  
  3240.     for (i = 0; i < MAX_PLAYERS; i++)
  3241.         if (Newdemo_players_cloaked & (1 << i))
  3242.             Players[i].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
  3243.  
  3244.     if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
  3245.         Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
  3246.     
  3247.     if (Newdemo_vcr_state == ND_STATE_PAUSED)           // render a frame or not
  3248.         return;
  3249.  
  3250.     Fuelcen_control_center_destroyed = 0;
  3251.     Fuelcen_seconds_left = -1;
  3252.     PALETTE_FLASH_SET(0,0,0);       //clear flash
  3253.  
  3254.     if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
  3255.     {
  3256.         level = Current_level_num;
  3257.         if (NewdemoFrameCount == 0)
  3258.             return;
  3259.         else if ((Newdemo_vcr_state == ND_STATE_REWINDING) && (NewdemoFrameCount < 10)) {
  3260.             newdemo_goto_beginning();
  3261.             return;
  3262.         }
  3263.         if (Newdemo_vcr_state == ND_STATE_REWINDING)
  3264.             frames_back = 10;
  3265.         else
  3266.             frames_back = 1;
  3267.         if (Newdemo_at_eof) {
  3268. #ifdef SHAREWARE
  3269.             fseek(infile, -2, SEEK_END);
  3270. #else
  3271.             fseek(infile, 11, SEEK_CUR);
  3272. #endif
  3273.         }
  3274.         newdemo_back_frames(frames_back);
  3275.  
  3276.         if (level != Current_level_num)
  3277.             newdemo_pop_ctrlcen_triggers();
  3278.  
  3279.         if (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD) {
  3280.             if (level != Current_level_num)
  3281.                 newdemo_back_frames(1);
  3282.             Newdemo_vcr_state = ND_STATE_PAUSED;
  3283.         }
  3284.     }
  3285.     else if (Newdemo_vcr_state == ND_STATE_FASTFORWARD) {
  3286.         if (!Newdemo_at_eof)
  3287.         {
  3288.             for (i = 0; i < 10; i++)
  3289.             {
  3290.                 if (newdemo_read_frame_information() == -1)
  3291.                 {
  3292.                     if (Newdemo_at_eof)
  3293.                         Newdemo_vcr_state = ND_STATE_PAUSED;
  3294.                     else
  3295.                         newdemo_stop_playback();
  3296.                     break;
  3297.                 }
  3298.             }
  3299.         }
  3300.         else
  3301.             Newdemo_vcr_state = ND_STATE_PAUSED;
  3302.     }
  3303.     else if (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD) {
  3304.         if (!Newdemo_at_eof) {
  3305.             level = Current_level_num;
  3306.             if (newdemo_read_frame_information() == -1) {
  3307.                 if (!Newdemo_at_eof)
  3308.                     newdemo_stop_playback();
  3309.             }
  3310.             if (level != Current_level_num) {
  3311.                 if (newdemo_read_frame_information() == -1) {
  3312.                     if (!Newdemo_at_eof)
  3313.                         newdemo_stop_playback();
  3314.                 }
  3315.             }
  3316.             Newdemo_vcr_state = ND_STATE_PAUSED;
  3317.         } else
  3318.             Newdemo_vcr_state = ND_STATE_PAUSED;
  3319.     }
  3320.     else {
  3321.  
  3322. //  First, uptate the total playback time to date.  Then we check to see
  3323. //  if we need to change the playback style to interpolate frames or
  3324. //  skip frames based on where the playback time is relative to the
  3325. //  recorded time.
  3326.  
  3327.         if (NewdemoFrameCount <= 0)
  3328.             nd_playback_total = nd_recorded_total;      // baseline total playback time
  3329.         else
  3330.             nd_playback_total += FrameTime;
  3331.         if ((playback_style == NORMAL_PLAYBACK) && (NewdemoFrameCount > 10))
  3332.             if ((nd_playback_total * INTERPOL_FACTOR) < nd_recorded_total) {
  3333.                 playback_style = INTERPOLATE_PLAYBACK;
  3334.                 nd_playback_total = nd_recorded_total + FrameTime;      // baseline playback time
  3335.                 base_interpol_time = nd_recorded_total;
  3336.                 d_recorded = nd_recorded_time;                                  // baseline delta recorded
  3337.             }
  3338.         if ((playback_style == NORMAL_PLAYBACK) && (NewdemoFrameCount > 10))
  3339.             if (nd_playback_total > nd_recorded_total)
  3340.                 playback_style = SKIP_PLAYBACK;
  3341.  
  3342.                     
  3343.         if ((playback_style == INTERPOLATE_PLAYBACK) && Newdemo_do_interpolate) {
  3344.             fix d_play = 0;
  3345.  
  3346.             if (nd_recorded_total - nd_playback_total < FrameTime) {
  3347.                 d_recorded = nd_recorded_total - nd_playback_total;
  3348.  
  3349.                 while (nd_recorded_total - nd_playback_total < FrameTime) {
  3350.                     object *cur_objs;
  3351.                     int i, j, num_objs, level;
  3352.  
  3353.                     num_objs = Highest_object_index;
  3354.                     cur_objs = (object *)malloc(sizeof(object) * (num_objs + 1));
  3355.                     if (cur_objs == NULL) {
  3356.                         Warning ("Couldn't get %d bytes for objects in interpolate playback\n", sizeof(object) * num_objs);
  3357.                         break;
  3358.                     }
  3359.                     for (i = 0; i <= num_objs; i++)
  3360.                         memcpy(&(cur_objs[i]), &(Objects[i]), sizeof(object));
  3361.  
  3362.                     level = Current_level_num;
  3363.                     if (newdemo_read_frame_information() == -1) {
  3364.                         free(cur_objs);
  3365.                         newdemo_stop_playback();
  3366.                         return;
  3367.                     }
  3368.                     if (level != Current_level_num) {
  3369.                         free(cur_objs);
  3370.                         if (newdemo_read_frame_information() == -1)
  3371.                             newdemo_stop_playback();
  3372.                         break;
  3373.                     }
  3374.  
  3375. //  for each new object in the frame just read in, determine if there is
  3376. //  a corresponding object that we have been interpolating.  If so, then
  3377. //  copy that interpolated object to the new Objects array so that the
  3378. //  interpolated position and orientation can be preserved.
  3379.  
  3380.                     for (i = 0; i <= num_objs; i++) {
  3381.                         for (j = 0; j <= Highest_object_index; j++) {
  3382.                             if (cur_objs[i].signature == Objects[j].signature) {
  3383.                                 memcpy(&(Objects[j].orient), &(cur_objs[i].orient), sizeof(vms_matrix));
  3384.                                 memcpy(&(Objects[j].pos), &(cur_objs[i].pos), sizeof(vms_vector));
  3385.                                 break;
  3386.                             }
  3387.                         }
  3388.                     }
  3389.                     free(cur_objs);
  3390.                     d_recorded += nd_recorded_time;
  3391.                     base_interpol_time = nd_playback_total - FrameTime;
  3392.                 }
  3393.             }
  3394.  
  3395.             d_play = nd_playback_total - base_interpol_time;
  3396.             interpolate_frame(d_play, d_recorded);
  3397.             return;
  3398.         }
  3399.         else {
  3400. //          mprintf ((0, "*"));
  3401.             if (newdemo_read_frame_information() == -1) {
  3402.                 newdemo_stop_playback();
  3403.                 return;
  3404.             }
  3405.             if (playback_style == SKIP_PLAYBACK) {
  3406. //              mprintf ((0, "."));
  3407.                 while (nd_playback_total > nd_recorded_total) {
  3408.                     if (newdemo_read_frame_information() == -1) {
  3409.                         newdemo_stop_playback();
  3410.                         return;
  3411.                     }
  3412.                 }
  3413.             }
  3414.         }
  3415.     }
  3416. }
  3417.  
  3418. void newdemo_start_recording()
  3419. {
  3420.     outfile = fopen( DEMO_FILENAME, "wb" );
  3421.     newdemo_record_start_demo();
  3422. }
  3423.  
  3424. char demoname_allowed_chars[] = "azAZ09__--";
  3425. void newdemo_stop_recording()
  3426. {
  3427.     newmenu_item m[6];
  3428.     int l, exit;
  3429.     static char filename[9] = "", *s;
  3430.     static ubyte tmpcnt = 0;
  3431.     ubyte cloaked = 0;
  3432.     char fullname[15];
  3433. #ifndef SHAREWARE
  3434.     unsigned short byte_count = 0;
  3435. #endif
  3436.  
  3437.     nd_write_byte(ND_EVENT_EOF);
  3438.     nd_write_short(frame_bytes_written - 1);
  3439.     if (Game_mode & GM_MULTI) {
  3440.         for (l = 0; l < N_players; l++) {
  3441.             if (Players[l].flags & PLAYER_FLAGS_CLOAKED)
  3442.                 cloaked |= (1 << l);
  3443.         }
  3444.         nd_write_byte(cloaked);
  3445.         nd_write_byte(ND_EVENT_EOF);
  3446.     } else {
  3447.         nd_write_short(ND_EVENT_EOF);
  3448.     }
  3449.     nd_write_short(ND_EVENT_EOF);
  3450.     nd_write_int(ND_EVENT_EOF);
  3451.  
  3452. #ifndef SHAREWARE
  3453.     byte_count += 10;       // from frame_bytes_written
  3454.  
  3455.     nd_write_byte((byte)(f2ir(Players[Player_num].energy)));
  3456.     nd_write_byte((byte)(f2ir(Players[Player_num].shields)));
  3457.     nd_write_int(Players[Player_num].flags);        // be sure players flags are set
  3458.     nd_write_byte((byte)Primary_weapon);
  3459.     nd_write_byte((byte)Secondary_weapon);
  3460.     byte_count += 8;
  3461.  
  3462.     for (l = 0; l < MAX_PRIMARY_WEAPONS; l++)
  3463.         nd_write_short((short)Players[Player_num].primary_ammo[l]);
  3464.  
  3465.     for (l = 0; l < MAX_SECONDARY_WEAPONS; l++)
  3466.         nd_write_short((short)Players[Player_num].secondary_ammo[l]);
  3467.     byte_count += (sizeof(short) * (MAX_PRIMARY_WEAPONS + MAX_SECONDARY_WEAPONS));
  3468.  
  3469.     nd_write_byte(Players[Player_num].laser_level);
  3470.     byte_count++;
  3471.  
  3472.     if (Game_mode & GM_MULTI) {
  3473.         nd_write_byte((byte)N_players);
  3474.         byte_count++;
  3475.         for (l = 0; l < N_players; l++) {
  3476.             nd_write_string(Players[l].callsign);
  3477.             byte_count += (strlen(Players[l].callsign) + 2);
  3478.             nd_write_byte(Players[l].connected);
  3479.             if (Game_mode & GM_MULTI_COOP) {
  3480.                 nd_write_int(Players[l].score);
  3481.                 byte_count += 5;
  3482.             } else {
  3483.                 nd_write_short((short)Players[l].net_killed_total);
  3484.                 nd_write_short((short)Players[l].net_kills_total);
  3485.                 byte_count += 5;
  3486.             }
  3487.         }
  3488.     } else {
  3489.         nd_write_int(Players[Player_num].score);
  3490.         byte_count += 4;
  3491.     }
  3492.     nd_write_short(byte_count);
  3493. #endif
  3494.  
  3495.     nd_write_byte(Current_level_num);
  3496.     nd_write_byte(ND_EVENT_EOF);
  3497.  
  3498.     l = ftell(outfile);
  3499.     fclose(outfile);
  3500.     Newdemo_state = ND_STATE_NORMAL;
  3501.     gr_palette_load( gr_palette );
  3502.  
  3503.     if (filename[0] != '\0') {
  3504.         int num, i = strlen(filename) - 1;
  3505.         char newfile[15];
  3506.  
  3507.         while (isdigit(filename[i])) {
  3508.             i--;
  3509.             if (i == -1)
  3510.                 break;
  3511.         }
  3512.         i++;
  3513.         num = atoi(&(filename[i]));
  3514.         num++;
  3515.         filename[i] = '\0';
  3516.         sprintf (newfile, "%s%d", filename, num);
  3517.         strncpy(filename, newfile, 8);
  3518.         filename[8] = '\0';
  3519.     }
  3520.  
  3521. try_again:
  3522.     ;
  3523.  
  3524.     Newmenu_allowed_chars = demoname_allowed_chars;
  3525.     if (!Newdemo_no_space) {
  3526.         m[0].type=NM_TYPE_INPUT; m[0].text_len = 8; m[0].text = filename;
  3527.         exit = newmenu_do( NULL, TXT_SAVE_DEMO_AS, 1, &(m[0]), NULL );
  3528.     } else if (Newdemo_no_space == 1) {
  3529.         m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_DEMO_SAVE_BAD;
  3530.         m[ 1].type = NM_TYPE_INPUT;m[ 1].text_len = 8; m[1].text = filename;
  3531.         exit = newmenu_do( NULL, NULL, 2, m, NULL );
  3532.     } else if (Newdemo_no_space == 2) {
  3533.         m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_DEMO_SAVE_NOSPACE;
  3534.         m[ 1].type = NM_TYPE_INPUT;m[ 1].text_len = 8; m[1].text = filename;
  3535.         exit = newmenu_do( NULL, NULL, 2, m, NULL );
  3536.     }
  3537.     Newmenu_allowed_chars = NULL;
  3538.  
  3539.     if (exit == -2) {                   // got bumped out from network menu
  3540.         char save_file[15];
  3541.  
  3542.         if (filename[0] != '\0') {
  3543.             strcpy(save_file, filename);
  3544.             strcat(save_file, ".dem");
  3545.         } else 
  3546.             sprintf (save_file, "tmp%d.dem", tmpcnt++);
  3547.         remove(save_file);
  3548.         rename(DEMO_FILENAME, save_file);
  3549.         return;
  3550.     }
  3551.     if (exit == -1) {                   // pressed ESC
  3552.         remove(DEMO_FILENAME);      // might as well remove the file
  3553.         return;                         // return without doing anything
  3554.     }
  3555.     
  3556.     if (filename[0]==0) //null string
  3557.         goto try_again;
  3558.  
  3559.     //check to make sure name is ok
  3560.     for (s=filename;*s;s++)
  3561.         if (!isalnum(*s) && *s!='_') {
  3562.             nm_messagebox1(NULL, NULL,1,TXT_CONTINUE, TXT_DEMO_USE_LETTERS);
  3563.             goto try_again;
  3564.         }
  3565.  
  3566.     if (Newdemo_no_space)
  3567.         strcpy(fullname, m[1].text);
  3568.     else
  3569.         strcpy(fullname, m[0].text);
  3570.     strcat(fullname, ".dem");
  3571.     remove(fullname);
  3572.     rename(DEMO_FILENAME, fullname);
  3573. }
  3574.  
  3575. void newdemo_start_playback(char * filename)
  3576. {
  3577.     // struct find_t find;
  3578.     int rnd_demo = 0;
  3579.     glob_t glob_ret;
  3580.  
  3581.     if (filename==NULL) {
  3582.         glob_ret.gl_offs=0;
  3583.         if (!glob("*.dem",0,NULL,&glob_ret)&&glob_ret.gl_pathc)
  3584.             filename=glob_ret.gl_pathv[rand()%glob_ret.gl_pathc];
  3585.         if ( filename==NULL) return;
  3586.     }
  3587.  
  3588.     if (!filename)
  3589.         return;
  3590.     
  3591.     infile = fopen( filename, "rb" );
  3592. #ifdef USE_CD
  3593.     if (infile==NULL)   {
  3594.         // Read demo from CD??
  3595.         if ( strlen(destsat_cdpath) )   {
  3596.             char temp_spec[128];
  3597.             strcpy( temp_spec, destsat_cdpath );
  3598.             strcat( temp_spec, filename );
  3599.             infile = fopen( temp_spec, "rb" );
  3600.         }
  3601.     }
  3602. #endif
  3603.     if (infile==NULL)   {
  3604.         mprintf( (0, "Error reading '%s'\n", filename ));
  3605.         return;
  3606.     }
  3607.  
  3608.     nd_bad_read = 0;
  3609.     #ifdef NETWORK
  3610.     change_playernum_to(0);                     // force playernum to 0
  3611.     #endif
  3612.     strncpy(nd_save_callsign, Players[Player_num].callsign, CALLSIGN_LEN);
  3613.     Viewer = ConsoleObject = &Objects[0];   // play properly as if console player
  3614.     if (newdemo_read_demo_start(rnd_demo)) {
  3615.         fclose(infile);
  3616.         return;
  3617.     }
  3618.  
  3619.     Game_mode = GM_NORMAL;
  3620.     Newdemo_state = ND_STATE_PLAYBACK;
  3621.     Newdemo_vcr_state = ND_STATE_PLAYBACK;
  3622.     Newdemo_old_cockpit = Cockpit_mode;
  3623.     Newdemo_size = filelength(fileno(infile));
  3624.     nd_bad_read = 0;
  3625.     Newdemo_at_eof = 0;
  3626.     NewdemoFrameCount = 0;
  3627.     Newdemo_players_cloaked = 0;
  3628.     playback_style = NORMAL_PLAYBACK;
  3629.     Function_mode = FMODE_GAME;
  3630.     newdemo_playback_one_frame();       // this one loads new level
  3631.     newdemo_playback_one_frame();       // get all of the objects to renderb game
  3632. }
  3633.  
  3634. void newdemo_stop_playback()
  3635. {
  3636.     fclose( infile );
  3637.     Newdemo_state = ND_STATE_NORMAL;
  3638.     #ifdef NETWORK
  3639.     change_playernum_to(0);                     //this is reality
  3640.     #endif
  3641.     strncpy(Players[Player_num].callsign, nd_save_callsign, CALLSIGN_LEN);
  3642.     Cockpit_mode = Newdemo_old_cockpit;
  3643.     Game_mode = GM_GAME_OVER;
  3644.     Function_mode = FMODE_MENU;
  3645.     longjmp(LeaveGame,0);           // Exit game loop
  3646. }
  3647.  
  3648.  
  3649. #ifndef NDEBUG
  3650.  
  3651. #define BUF_SIZE 16384
  3652.  
  3653. void newdemo_strip_frames(char *outname, int bytes_to_strip)
  3654. {
  3655.     FILE *outfile;
  3656.     char *buf;
  3657.     int total_size, bytes_done, read_elems, bytes_back;
  3658.     int trailer_start, loc1, loc2, stop_loc, bytes_to_read;
  3659.     short last_frame_length;
  3660.  
  3661.     bytes_done = 0;
  3662.     total_size = filelength(fileno(infile));
  3663.     outfile = fopen(outname, "wb");
  3664.     if (outfile == NULL) {
  3665.         newmenu_item m[1];
  3666.  
  3667.         m[ 0].type = NM_TYPE_TEXT; m[ 0].text = "Can't open output file";
  3668.         newmenu_do( NULL, NULL, 1, m, NULL );
  3669.         newdemo_stop_playback();
  3670.         return;
  3671.     }
  3672.     buf = malloc(BUF_SIZE);
  3673.     if (buf == NULL) {
  3674.         newmenu_item m[1];
  3675.  
  3676.         m[ 0].type = NM_TYPE_TEXT; m[ 0].text = "Can't malloc output buffer";
  3677.         newmenu_do( NULL, NULL, 1, m, NULL );
  3678.         fclose(outfile);
  3679.         newdemo_stop_playback();
  3680.         return;
  3681.     }
  3682.     newdemo_goto_end();
  3683.     trailer_start = ftell(infile);
  3684.     fseek(infile, 11, SEEK_CUR);
  3685.     bytes_back = 0;
  3686.     while (bytes_back < bytes_to_strip) {
  3687.         loc1 = ftell(infile);
  3688. //      fseek(infile, -10, SEEK_CUR);
  3689. //      nd_read_short(&last_frame_length);          
  3690. //      fseek(infile, 8 - last_frame_length, SEEK_CUR);
  3691.         newdemo_back_frames(1);
  3692.         loc2 = ftell(infile);
  3693.         bytes_back += (loc1 - loc2);
  3694.     }
  3695.     fseek(infile, -10, SEEK_CUR);
  3696.     nd_read_short(&last_frame_length);
  3697.     fseek(infile, -3, SEEK_CUR);
  3698.     stop_loc = ftell(infile);
  3699.     fseek(infile, 0, SEEK_SET);
  3700.     while (stop_loc > 0) {
  3701.         if (stop_loc < BUF_SIZE)
  3702.             bytes_to_read = stop_loc;
  3703.         else
  3704.             bytes_to_read = BUF_SIZE;
  3705.         read_elems = fread(buf, 1, bytes_to_read, infile);
  3706.         fwrite(buf, 1, read_elems, outfile);
  3707.         stop_loc -= read_elems;
  3708.     }
  3709.     stop_loc = ftell(outfile);
  3710.     fseek(infile, trailer_start, SEEK_SET);
  3711.     while ((read_elems = fread(buf, 1, BUF_SIZE, infile)) != 0)
  3712.         fwrite(buf, 1, read_elems, outfile);
  3713.     fseek(outfile, stop_loc, SEEK_SET);
  3714.     fseek(outfile, 1, SEEK_CUR);
  3715.     fwrite(&last_frame_length, 2, 1, outfile);
  3716.     fclose(outfile);
  3717.     newdemo_stop_playback();
  3718.  
  3719. }
  3720.  
  3721. #endif
  3722.